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.
- package/LICENSE +21 -0
- package/README.md +103 -22
- package/deploy/.env.example +86 -0
- package/dist/config/index.d.ts +68 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +315 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/schema.d.ts +6 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +50 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/core/Bot.d.ts +91 -0
- package/dist/core/Bot.d.ts.map +1 -0
- package/dist/core/Bot.js +263 -0
- package/dist/core/Bot.js.map +1 -0
- package/dist/core/ConnectionPool.d.ts +125 -0
- package/dist/core/ConnectionPool.d.ts.map +1 -0
- package/dist/core/ConnectionPool.js +397 -0
- package/dist/core/ConnectionPool.js.map +1 -0
- package/dist/core/SSHClient.d.ts +112 -0
- package/dist/core/SSHClient.d.ts.map +1 -0
- package/dist/core/SSHClient.js +367 -0
- package/dist/core/SSHClient.js.map +1 -0
- package/dist/core/ServerManager.d.ts +80 -0
- package/dist/core/ServerManager.d.ts.map +1 -0
- package/dist/core/ServerManager.js +207 -0
- package/dist/core/ServerManager.js.map +1 -0
- package/dist/core/index.d.ts +8 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +8 -0
- package/dist/core/index.js.map +1 -0
- package/dist/errors/AuthError.d.ts +30 -0
- package/dist/errors/AuthError.d.ts.map +1 -0
- package/dist/errors/AuthError.js +35 -0
- package/dist/errors/AuthError.js.map +1 -0
- package/dist/errors/BaseError.d.ts +17 -0
- package/dist/errors/BaseError.d.ts.map +1 -0
- package/dist/errors/BaseError.js +34 -0
- package/dist/errors/BaseError.js.map +1 -0
- package/dist/errors/ConfigurationError.d.ts +24 -0
- package/dist/errors/ConfigurationError.d.ts.map +1 -0
- package/dist/errors/ConfigurationError.js +24 -0
- package/dist/errors/ConfigurationError.js.map +1 -0
- package/dist/errors/PoolError.d.ts +21 -0
- package/dist/errors/PoolError.d.ts.map +1 -0
- package/dist/errors/PoolError.js +30 -0
- package/dist/errors/PoolError.js.map +1 -0
- package/dist/errors/SSHError.d.ts +24 -0
- package/dist/errors/SSHError.d.ts.map +1 -0
- package/dist/errors/SSHError.js +38 -0
- package/dist/errors/SSHError.js.map +1 -0
- package/dist/errors/StorageError.d.ts +24 -0
- package/dist/errors/StorageError.d.ts.map +1 -0
- package/dist/errors/StorageError.js +35 -0
- package/dist/errors/StorageError.js.map +1 -0
- package/dist/errors/ValidationError.d.ts +29 -0
- package/dist/errors/ValidationError.d.ts.map +1 -0
- package/dist/errors/ValidationError.js +35 -0
- package/dist/errors/ValidationError.js.map +1 -0
- package/dist/errors/index.d.ts +11 -0
- package/dist/errors/index.d.ts.map +1 -0
- package/dist/errors/index.js +18 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/handlers/BaseHandler.d.ts +50 -0
- package/dist/handlers/BaseHandler.d.ts.map +1 -0
- package/dist/handlers/BaseHandler.js +87 -0
- package/dist/handlers/BaseHandler.js.map +1 -0
- package/dist/handlers/CommandHandler.d.ts +23 -0
- package/dist/handlers/CommandHandler.d.ts.map +1 -0
- package/dist/handlers/CommandHandler.js +99 -0
- package/dist/handlers/CommandHandler.js.map +1 -0
- package/dist/handlers/HealthHandler.d.ts +25 -0
- package/dist/handlers/HealthHandler.d.ts.map +1 -0
- package/dist/handlers/HealthHandler.js +51 -0
- package/dist/handlers/HealthHandler.js.map +1 -0
- package/dist/handlers/HelpHandler.d.ts +32 -0
- package/dist/handlers/HelpHandler.d.ts.map +1 -0
- package/dist/handlers/HelpHandler.js +76 -0
- package/dist/handlers/HelpHandler.js.map +1 -0
- package/dist/handlers/ServerHandler.d.ts +72 -0
- package/dist/handlers/ServerHandler.d.ts.map +1 -0
- package/dist/handlers/ServerHandler.js +272 -0
- package/dist/handlers/ServerHandler.js.map +1 -0
- package/dist/handlers/index.d.ts +9 -0
- package/dist/handlers/index.d.ts.map +1 -0
- package/dist/handlers/index.js +9 -0
- package/dist/handlers/index.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +348 -0
- package/dist/index.js.map +1 -0
- package/dist/middleware/AuthMiddleware.d.ts +28 -0
- package/dist/middleware/AuthMiddleware.d.ts.map +1 -0
- package/dist/middleware/AuthMiddleware.js +49 -0
- package/dist/middleware/AuthMiddleware.js.map +1 -0
- package/dist/middleware/RateLimitMiddleware.d.ts +23 -0
- package/dist/middleware/RateLimitMiddleware.d.ts.map +1 -0
- package/dist/middleware/RateLimitMiddleware.js +34 -0
- package/dist/middleware/RateLimitMiddleware.js.map +1 -0
- package/dist/middleware/index.d.ts +6 -0
- package/dist/middleware/index.d.ts.map +1 -0
- package/dist/middleware/index.js +6 -0
- package/dist/middleware/index.js.map +1 -0
- package/dist/services/BackupService.d.ts +119 -0
- package/dist/services/BackupService.d.ts.map +1 -0
- package/dist/services/BackupService.js +313 -0
- package/dist/services/BackupService.js.map +1 -0
- package/dist/services/CryptoService.d.ts +37 -0
- package/dist/services/CryptoService.d.ts.map +1 -0
- package/dist/services/CryptoService.js +108 -0
- package/dist/services/CryptoService.js.map +1 -0
- package/dist/services/HealthService.d.ts +126 -0
- package/dist/services/HealthService.d.ts.map +1 -0
- package/dist/services/HealthService.js +213 -0
- package/dist/services/HealthService.js.map +1 -0
- package/dist/services/LoggingService.d.ts +115 -0
- package/dist/services/LoggingService.d.ts.map +1 -0
- package/dist/services/LoggingService.js +334 -0
- package/dist/services/LoggingService.js.map +1 -0
- package/dist/services/MonitoringService.d.ts +119 -0
- package/dist/services/MonitoringService.d.ts.map +1 -0
- package/dist/services/MonitoringService.js +267 -0
- package/dist/services/MonitoringService.js.map +1 -0
- package/dist/services/NotificationService.d.ts +132 -0
- package/dist/services/NotificationService.d.ts.map +1 -0
- package/dist/services/NotificationService.js +297 -0
- package/dist/services/NotificationService.js.map +1 -0
- package/dist/services/RateLimiter.d.ts +51 -0
- package/dist/services/RateLimiter.d.ts.map +1 -0
- package/dist/services/RateLimiter.js +141 -0
- package/dist/services/RateLimiter.js.map +1 -0
- package/dist/services/ValidationService.d.ts +49 -0
- package/dist/services/ValidationService.d.ts.map +1 -0
- package/dist/services/ValidationService.js +158 -0
- package/dist/services/ValidationService.js.map +1 -0
- package/dist/services/index.d.ts +12 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/index.js +12 -0
- package/dist/services/index.js.map +1 -0
- package/dist/types/Bot.d.ts +63 -0
- package/dist/types/Bot.d.ts.map +1 -0
- package/dist/types/Bot.js +5 -0
- package/dist/types/Bot.js.map +1 -0
- package/dist/types/Config.d.ts +57 -0
- package/dist/types/Config.d.ts.map +1 -0
- package/dist/types/Config.js +5 -0
- package/dist/types/Config.js.map +1 -0
- package/dist/types/Errors.d.ts +37 -0
- package/dist/types/Errors.d.ts.map +1 -0
- package/dist/types/Errors.js +34 -0
- package/dist/types/Errors.js.map +1 -0
- package/dist/types/SSH.d.ts +56 -0
- package/dist/types/SSH.d.ts.map +1 -0
- package/dist/types/SSH.js +6 -0
- package/dist/types/SSH.js.map +1 -0
- package/dist/types/Server.d.ts +39 -0
- package/dist/types/Server.d.ts.map +1 -0
- package/dist/types/Server.js +5 -0
- package/dist/types/Server.js.map +1 -0
- package/dist/types/index.d.ts +10 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +6 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/commandUtils.d.ts +25 -0
- package/dist/utils/commandUtils.d.ts.map +1 -0
- package/dist/utils/commandUtils.js +94 -0
- package/dist/utils/commandUtils.js.map +1 -0
- package/dist/utils/fileUtils.d.ts +40 -0
- package/dist/utils/fileUtils.d.ts.map +1 -0
- package/dist/utils/fileUtils.js +114 -0
- package/dist/utils/fileUtils.js.map +1 -0
- package/dist/utils/index.d.ts +7 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +7 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/pathUtils.d.ts +40 -0
- package/dist/utils/pathUtils.d.ts.map +1 -0
- package/dist/utils/pathUtils.js +140 -0
- package/dist/utils/pathUtils.js.map +1 -0
- package/package.json +31 -5
- package/scripts/build.sh +20 -0
- package/scripts/postinstall.js +87 -0
- package/scripts/release.sh +22 -0
- package/scripts/setup-env.js +237 -0
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Command sanitization utility
|
|
3
|
+
* Provides safe command execution by sanitizing and validating commands
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Dangerous patterns that should be blocked or warned about
|
|
7
|
+
*/
|
|
8
|
+
const DANGEROUS_PATTERNS = [
|
|
9
|
+
{ pattern: /;\s*rm\s+-rf/i, description: "rm -rf chain" },
|
|
10
|
+
{ pattern: /\|\s*rm\s+/i, description: "pipe to rm" },
|
|
11
|
+
{ pattern: />\s*\/dev\//i, description: "device redirection" },
|
|
12
|
+
{ pattern: /\$\([^)]+\)/, description: "command substitution" },
|
|
13
|
+
{ pattern: /`[^`]+`/, description: "backtick execution" },
|
|
14
|
+
{ pattern: /\$\{[^}]+\}/, description: "variable expansion" },
|
|
15
|
+
{ pattern: /&&\s*rm/i, description: "chained rm" },
|
|
16
|
+
{ pattern: /\|\|\s*rm/i, description: "or-chained rm" },
|
|
17
|
+
{ pattern: />\s*\//i, description: "root file write" },
|
|
18
|
+
{ pattern: /<\s*\//i, description: "root file read" },
|
|
19
|
+
{ pattern: /sudo\s+/i, description: "sudo commands" },
|
|
20
|
+
{ pattern: /chmod\s+777/i, description: "dangerous permissions" },
|
|
21
|
+
{ pattern: /chown\s+.*:.*\s+\//i, description: "ownership changes" },
|
|
22
|
+
];
|
|
23
|
+
/**
|
|
24
|
+
* Shell metacharacters that need escaping
|
|
25
|
+
*/
|
|
26
|
+
const SHELL_METACHARACTERS = /[;&|`$\\]/g;
|
|
27
|
+
/**
|
|
28
|
+
* Sanitize a command for safe execution
|
|
29
|
+
*/
|
|
30
|
+
export function sanitizeCommand(command) {
|
|
31
|
+
const warnings = [];
|
|
32
|
+
let sanitized = command.trim();
|
|
33
|
+
// Check for dangerous patterns
|
|
34
|
+
for (const { pattern, description } of DANGEROUS_PATTERNS) {
|
|
35
|
+
if (pattern.test(sanitized)) {
|
|
36
|
+
warnings.push(`Dangerous pattern detected: ${description}`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
// Remove null bytes
|
|
40
|
+
sanitized = sanitized.replace(/\0/g, "");
|
|
41
|
+
// Escape shell metacharacters for SSH
|
|
42
|
+
sanitized = sanitized.replace(SHELL_METACHARACTERS, "\\$&");
|
|
43
|
+
return {
|
|
44
|
+
original: command,
|
|
45
|
+
sanitized,
|
|
46
|
+
warnings,
|
|
47
|
+
isSafe: warnings.length === 0,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Validate a command for execution
|
|
52
|
+
*/
|
|
53
|
+
export function validateCommand(command) {
|
|
54
|
+
if (!command || command.trim().length === 0) {
|
|
55
|
+
return { valid: false, error: "Command cannot be empty" };
|
|
56
|
+
}
|
|
57
|
+
if (command.length > 10000) {
|
|
58
|
+
return {
|
|
59
|
+
valid: false,
|
|
60
|
+
error: "Command is too long (max 10000 characters)",
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
const sanitized = sanitizeCommand(command);
|
|
64
|
+
// Block commands with dangerous patterns
|
|
65
|
+
if (sanitized.warnings.length > 0) {
|
|
66
|
+
return {
|
|
67
|
+
valid: false,
|
|
68
|
+
error: `Command contains dangerous patterns: ${sanitized.warnings.join(", ")}`,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
return { valid: true, data: sanitized };
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Parse command arguments safely
|
|
75
|
+
*/
|
|
76
|
+
export function parseCommandArgs(input) {
|
|
77
|
+
const trimmed = input.trim();
|
|
78
|
+
const spaceIndex = trimmed.indexOf(" ");
|
|
79
|
+
if (spaceIndex === -1) {
|
|
80
|
+
return { command: trimmed, args: "" };
|
|
81
|
+
}
|
|
82
|
+
return {
|
|
83
|
+
command: trimmed.slice(0, spaceIndex),
|
|
84
|
+
args: trimmed.slice(spaceIndex + 1).trim(),
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Escape a string for safe use in shell
|
|
89
|
+
*/
|
|
90
|
+
export function escapeShellArg(arg) {
|
|
91
|
+
// Use single quotes and escape any existing single quotes
|
|
92
|
+
return `'${arg.replace(/'/g, "'\\''")}'`;
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=commandUtils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commandUtils.js","sourceRoot":"","sources":["../../src/utils/commandUtils.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Async file operations utility
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Check if a file exists
|
|
6
|
+
*/
|
|
7
|
+
export declare function fileExists(filePath: string): Promise<boolean>;
|
|
8
|
+
/**
|
|
9
|
+
* Ensure a directory exists, create if it doesn't
|
|
10
|
+
*/
|
|
11
|
+
export declare function ensureDir(dirPath: string): Promise<void>;
|
|
12
|
+
/**
|
|
13
|
+
* Read a file as string
|
|
14
|
+
*/
|
|
15
|
+
export declare function readFile(filePath: string): Promise<string>;
|
|
16
|
+
/**
|
|
17
|
+
* Read a file as JSON
|
|
18
|
+
*/
|
|
19
|
+
export declare function readJsonFile<T>(filePath: string): Promise<T>;
|
|
20
|
+
/**
|
|
21
|
+
* Write string to a file
|
|
22
|
+
*/
|
|
23
|
+
export declare function writeFile(filePath: string, content: string): Promise<void>;
|
|
24
|
+
/**
|
|
25
|
+
* Write object as JSON to a file
|
|
26
|
+
*/
|
|
27
|
+
export declare function writeJsonFile<T>(filePath: string, data: T, pretty?: boolean): Promise<void>;
|
|
28
|
+
/**
|
|
29
|
+
* Delete a file
|
|
30
|
+
*/
|
|
31
|
+
export declare function deleteFile(filePath: string): Promise<void>;
|
|
32
|
+
/**
|
|
33
|
+
* Get file stats
|
|
34
|
+
*/
|
|
35
|
+
export declare function getFileStats(filePath: string): Promise<{
|
|
36
|
+
size: number;
|
|
37
|
+
createdAt: Date;
|
|
38
|
+
modifiedAt: Date;
|
|
39
|
+
}>;
|
|
40
|
+
//# sourceMappingURL=fileUtils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fileUtils.d.ts","sourceRoot":"","sources":["../../src/utils/fileUtils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAUH;;GAEG;AACH,wBAAsB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAOnE;AAED;;GAEG;AACH,wBAAsB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAS9D;AAED;;GAEG;AACH,wBAAsB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAahE;AAED;;GAEG;AACH,wBAAsB,YAAY,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAUlE;AAED;;GAEG;AACH,wBAAsB,SAAS,CAC7B,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,IAAI,CAAC,CAef;AAED;;GAEG;AACH,wBAAsB,aAAa,CAAC,CAAC,EACnC,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,CAAC,EACP,MAAM,GAAE,OAAc,GACrB,OAAO,CAAC,IAAI,CAAC,CAGf;AAED;;GAEG;AACH,wBAAsB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAYhE;AAED;;GAEG;AACH,wBAAsB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;IAC5D,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,IAAI,CAAC;IAChB,UAAU,EAAE,IAAI,CAAC;CAClB,CAAC,CAiBD"}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Async file operations utility
|
|
3
|
+
*/
|
|
4
|
+
import { promises as fs } from "fs";
|
|
5
|
+
import * as path from "path";
|
|
6
|
+
import { FileNotFoundError, FileReadError, FileWriteError, } from "../errors/index.js";
|
|
7
|
+
/**
|
|
8
|
+
* Check if a file exists
|
|
9
|
+
*/
|
|
10
|
+
export async function fileExists(filePath) {
|
|
11
|
+
try {
|
|
12
|
+
await fs.access(filePath);
|
|
13
|
+
return true;
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Ensure a directory exists, create if it doesn't
|
|
21
|
+
*/
|
|
22
|
+
export async function ensureDir(dirPath) {
|
|
23
|
+
try {
|
|
24
|
+
await fs.mkdir(dirPath, { recursive: true });
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
throw new FileWriteError(dirPath, error instanceof Error ? error : new Error(String(error)));
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Read a file as string
|
|
32
|
+
*/
|
|
33
|
+
export async function readFile(filePath) {
|
|
34
|
+
try {
|
|
35
|
+
const content = await fs.readFile(filePath, "utf-8");
|
|
36
|
+
return content;
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
if (error.code === "ENOENT") {
|
|
40
|
+
throw new FileNotFoundError(filePath);
|
|
41
|
+
}
|
|
42
|
+
throw new FileReadError(filePath, error instanceof Error ? error : new Error(String(error)));
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Read a file as JSON
|
|
47
|
+
*/
|
|
48
|
+
export async function readJsonFile(filePath) {
|
|
49
|
+
const content = await readFile(filePath);
|
|
50
|
+
try {
|
|
51
|
+
return JSON.parse(content);
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
throw new FileReadError(filePath, error instanceof Error ? error : new Error(String(error)));
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Write string to a file
|
|
59
|
+
*/
|
|
60
|
+
export async function writeFile(filePath, content) {
|
|
61
|
+
try {
|
|
62
|
+
// Ensure parent directory exists
|
|
63
|
+
const dir = path.dirname(filePath);
|
|
64
|
+
await ensureDir(dir);
|
|
65
|
+
await fs.writeFile(filePath, content, "utf-8");
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
if (error instanceof FileNotFoundError || error instanceof FileWriteError) {
|
|
69
|
+
throw error;
|
|
70
|
+
}
|
|
71
|
+
throw new FileWriteError(filePath, error instanceof Error ? error : new Error(String(error)));
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Write object as JSON to a file
|
|
76
|
+
*/
|
|
77
|
+
export async function writeJsonFile(filePath, data, pretty = true) {
|
|
78
|
+
const content = pretty ? JSON.stringify(data, null, 2) : JSON.stringify(data);
|
|
79
|
+
await writeFile(filePath, content);
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Delete a file
|
|
83
|
+
*/
|
|
84
|
+
export async function deleteFile(filePath) {
|
|
85
|
+
try {
|
|
86
|
+
await fs.unlink(filePath);
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
if (error.code === "ENOENT") {
|
|
90
|
+
throw new FileNotFoundError(filePath);
|
|
91
|
+
}
|
|
92
|
+
throw new FileWriteError(filePath, error instanceof Error ? error : new Error(String(error)));
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Get file stats
|
|
97
|
+
*/
|
|
98
|
+
export async function getFileStats(filePath) {
|
|
99
|
+
try {
|
|
100
|
+
const stats = await fs.stat(filePath);
|
|
101
|
+
return {
|
|
102
|
+
size: stats.size,
|
|
103
|
+
createdAt: stats.birthtime,
|
|
104
|
+
modifiedAt: stats.mtime,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
if (error.code === "ENOENT") {
|
|
109
|
+
throw new FileNotFoundError(filePath);
|
|
110
|
+
}
|
|
111
|
+
throw new FileReadError(filePath, error instanceof Error ? error : new Error(String(error)));
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=fileUtils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fileUtils.js","sourceRoot":"","sources":["../../src/utils/fileUtils.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Path validation utility
|
|
3
|
+
* Provides safe path handling and traversal prevention
|
|
4
|
+
*/
|
|
5
|
+
import type { ValidationResult } from "../types/index.js";
|
|
6
|
+
/**
|
|
7
|
+
* Validate a path for safe file operations
|
|
8
|
+
*/
|
|
9
|
+
export declare function validatePath(inputPath: string, basePath?: string): ValidationResult<string>;
|
|
10
|
+
/**
|
|
11
|
+
* Validate a host address
|
|
12
|
+
*/
|
|
13
|
+
export declare function validateHost(host: string): ValidationResult<string>;
|
|
14
|
+
/**
|
|
15
|
+
* Validate a port number
|
|
16
|
+
*/
|
|
17
|
+
export declare function validatePort(port: number): ValidationResult<number>;
|
|
18
|
+
/**
|
|
19
|
+
* Parse and validate a port from string
|
|
20
|
+
*/
|
|
21
|
+
export declare function parsePort(portStr: string): ValidationResult<number>;
|
|
22
|
+
/**
|
|
23
|
+
* Get the directory name from a path
|
|
24
|
+
*/
|
|
25
|
+
export declare function getDirName(filePath: string): string;
|
|
26
|
+
/**
|
|
27
|
+
* Get the base name from a path
|
|
28
|
+
*/
|
|
29
|
+
export declare function getBaseName(filePath: string): string;
|
|
30
|
+
/**
|
|
31
|
+
* Join path segments safely
|
|
32
|
+
*/
|
|
33
|
+
export declare function joinPaths(...segments: string[]): string;
|
|
34
|
+
/**
|
|
35
|
+
* Expand tilde (~) in path to home directory
|
|
36
|
+
* @param inputPath - Path that may contain tilde
|
|
37
|
+
* @returns Path with tilde expanded to home directory
|
|
38
|
+
*/
|
|
39
|
+
export declare function expandTilde(inputPath: string): string;
|
|
40
|
+
//# sourceMappingURL=pathUtils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pathUtils.d.ts","sourceRoot":"","sources":["../../src/utils/pathUtils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AA2B1D;;GAEG;AACH,wBAAgB,YAAY,CAC1B,SAAS,EAAE,MAAM,EACjB,QAAQ,CAAC,EAAE,MAAM,GAChB,gBAAgB,CAAC,MAAM,CAAC,CAgC1B;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAgCnE;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAUnE;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAQnE;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,GAAG,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,CAEvD;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CASrD"}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Path validation utility
|
|
3
|
+
* Provides safe path handling and traversal prevention
|
|
4
|
+
*/
|
|
5
|
+
import * as path from "path";
|
|
6
|
+
/**
|
|
7
|
+
* Allowed base paths for file operations
|
|
8
|
+
*/
|
|
9
|
+
const ALLOWED_PATHS = [
|
|
10
|
+
"/home",
|
|
11
|
+
"/var/log",
|
|
12
|
+
"/var/www",
|
|
13
|
+
"/etc/nginx",
|
|
14
|
+
"/etc/systemd",
|
|
15
|
+
"/opt",
|
|
16
|
+
"/tmp",
|
|
17
|
+
];
|
|
18
|
+
/**
|
|
19
|
+
* Forbidden paths that should never be accessed
|
|
20
|
+
*/
|
|
21
|
+
const FORBIDDEN_PATHS = [
|
|
22
|
+
"/etc/shadow",
|
|
23
|
+
"/etc/passwd",
|
|
24
|
+
"/root/.ssh",
|
|
25
|
+
"/etc/ssh",
|
|
26
|
+
"/proc",
|
|
27
|
+
"/sys",
|
|
28
|
+
];
|
|
29
|
+
/**
|
|
30
|
+
* Validate a path for safe file operations
|
|
31
|
+
*/
|
|
32
|
+
export function validatePath(inputPath, basePath) {
|
|
33
|
+
// Resolve the path
|
|
34
|
+
const resolved = path.resolve(basePath || "/", inputPath);
|
|
35
|
+
const normalized = path.normalize(resolved);
|
|
36
|
+
// Check for path traversal attempts
|
|
37
|
+
if (inputPath.includes("..")) {
|
|
38
|
+
return { valid: false, error: "Path traversal detected" };
|
|
39
|
+
}
|
|
40
|
+
// Check for null bytes
|
|
41
|
+
if (inputPath.includes("\0")) {
|
|
42
|
+
return { valid: false, error: "Invalid null byte in path" };
|
|
43
|
+
}
|
|
44
|
+
// Check forbidden paths
|
|
45
|
+
for (const forbidden of FORBIDDEN_PATHS) {
|
|
46
|
+
if (normalized.startsWith(forbidden)) {
|
|
47
|
+
return { valid: false, error: "Access to path is forbidden" };
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
// Check allowed paths (if whitelist mode)
|
|
51
|
+
const isAllowed = ALLOWED_PATHS.some((allowed) => normalized.startsWith(allowed));
|
|
52
|
+
if (!isAllowed) {
|
|
53
|
+
return { valid: false, error: "Path is not in allowed list" };
|
|
54
|
+
}
|
|
55
|
+
return { valid: true, data: normalized };
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Validate a host address
|
|
59
|
+
*/
|
|
60
|
+
export function validateHost(host) {
|
|
61
|
+
if (!host || host.trim().length === 0) {
|
|
62
|
+
return { valid: false, error: "Host cannot be empty" };
|
|
63
|
+
}
|
|
64
|
+
const trimmed = host.trim();
|
|
65
|
+
// Check for valid hostname or IP format
|
|
66
|
+
const hostnameRegex = /^[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
|
|
67
|
+
const ipv4Regex = /^(\d{1,3}\.){3}\d{1,3}$/;
|
|
68
|
+
const ipv6Regex = /^([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$/;
|
|
69
|
+
const isValidHost = hostnameRegex.test(trimmed) ||
|
|
70
|
+
ipv4Regex.test(trimmed) ||
|
|
71
|
+
ipv6Regex.test(trimmed);
|
|
72
|
+
if (!isValidHost) {
|
|
73
|
+
return { valid: false, error: "Invalid host format" };
|
|
74
|
+
}
|
|
75
|
+
// Validate IPv4 octets if it's an IPv4 address
|
|
76
|
+
if (ipv4Regex.test(trimmed)) {
|
|
77
|
+
const octets = trimmed.split(".").map(Number);
|
|
78
|
+
const validOctets = octets.every((octet) => octet >= 0 && octet <= 255);
|
|
79
|
+
if (!validOctets) {
|
|
80
|
+
return { valid: false, error: "Invalid IPv4 address" };
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return { valid: true, data: trimmed };
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Validate a port number
|
|
87
|
+
*/
|
|
88
|
+
export function validatePort(port) {
|
|
89
|
+
if (!Number.isInteger(port)) {
|
|
90
|
+
return { valid: false, error: "Port must be an integer" };
|
|
91
|
+
}
|
|
92
|
+
if (port < 1 || port > 65535) {
|
|
93
|
+
return { valid: false, error: "Port must be between 1 and 65535" };
|
|
94
|
+
}
|
|
95
|
+
return { valid: true, data: port };
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Parse and validate a port from string
|
|
99
|
+
*/
|
|
100
|
+
export function parsePort(portStr) {
|
|
101
|
+
const parsed = parseInt(portStr, 10);
|
|
102
|
+
if (isNaN(parsed)) {
|
|
103
|
+
return { valid: false, error: "Invalid port number" };
|
|
104
|
+
}
|
|
105
|
+
return validatePort(parsed);
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Get the directory name from a path
|
|
109
|
+
*/
|
|
110
|
+
export function getDirName(filePath) {
|
|
111
|
+
return path.dirname(filePath);
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Get the base name from a path
|
|
115
|
+
*/
|
|
116
|
+
export function getBaseName(filePath) {
|
|
117
|
+
return path.basename(filePath);
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Join path segments safely
|
|
121
|
+
*/
|
|
122
|
+
export function joinPaths(...segments) {
|
|
123
|
+
return path.join(...segments);
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Expand tilde (~) in path to home directory
|
|
127
|
+
* @param inputPath - Path that may contain tilde
|
|
128
|
+
* @returns Path with tilde expanded to home directory
|
|
129
|
+
*/
|
|
130
|
+
export function expandTilde(inputPath) {
|
|
131
|
+
if (inputPath.startsWith("~/")) {
|
|
132
|
+
const home = process.env.HOME ?? "/root";
|
|
133
|
+
return path.join(home, inputPath.slice(2));
|
|
134
|
+
}
|
|
135
|
+
if (inputPath === "~") {
|
|
136
|
+
return process.env.HOME ?? "/root";
|
|
137
|
+
}
|
|
138
|
+
return inputPath;
|
|
139
|
+
}
|
|
140
|
+
//# sourceMappingURL=pathUtils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pathUtils.js","sourceRoot":"","sources":["../../src/utils/pathUtils.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,25 +1,51 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "telegram-ssh-bot",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.0",
|
|
4
|
+
"description": "A Telegram bot for secure SSH server management and remote command execution",
|
|
4
5
|
"type": "module",
|
|
5
6
|
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/index.js",
|
|
11
|
+
"types": "./dist/index.d.ts"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"author": "farhanzzg",
|
|
15
|
+
"license": "MIT",
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "git+https://github.com/farhanzzg/telegram-ssh.git"
|
|
19
|
+
},
|
|
20
|
+
"bugs": {
|
|
21
|
+
"url": "https://github.com/farhanzzg/telegram-ssh/issues"
|
|
22
|
+
},
|
|
23
|
+
"homepage": "https://github.com/farhanzzg/telegram-ssh#readme",
|
|
6
24
|
"bin": {
|
|
7
25
|
"telegram-ssh-bot": "./dist/index.js"
|
|
8
26
|
},
|
|
9
27
|
"files": [
|
|
10
28
|
"dist/**/*",
|
|
11
|
-
"
|
|
12
|
-
"
|
|
29
|
+
"scripts/**/*",
|
|
30
|
+
"deploy/.env.example",
|
|
31
|
+
"README.md"
|
|
13
32
|
],
|
|
14
33
|
"engines": {
|
|
15
34
|
"node": ">=18.0.0"
|
|
16
35
|
},
|
|
17
36
|
"keywords": [
|
|
18
37
|
"telegram",
|
|
38
|
+
"telegram-bot",
|
|
19
39
|
"ssh",
|
|
40
|
+
"ssh-client",
|
|
20
41
|
"bot",
|
|
21
42
|
"remote",
|
|
22
|
-
"server-management"
|
|
43
|
+
"server-management",
|
|
44
|
+
"server-administration",
|
|
45
|
+
"devops",
|
|
46
|
+
"remote-access",
|
|
47
|
+
"command-execution",
|
|
48
|
+
"terminal"
|
|
23
49
|
],
|
|
24
50
|
"pkg": {
|
|
25
51
|
"scripts": "dist/**/*.js",
|
|
@@ -54,7 +80,7 @@
|
|
|
54
80
|
"start": "node dist/index.js",
|
|
55
81
|
"dev": "tsc --watch",
|
|
56
82
|
"clean": "rm -rf dist",
|
|
57
|
-
"postinstall": "node
|
|
83
|
+
"postinstall": "node scripts/postinstall.js",
|
|
58
84
|
"build:binary": "npm run build && pkg .",
|
|
59
85
|
"build:binary:linux": "npm run build && pkg . --targets node18-linux-x64",
|
|
60
86
|
"build:binary:macos": "npm run build && pkg . --targets node18-macos-x64",
|
package/scripts/build.sh
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
set -e
|
|
3
|
+
|
|
4
|
+
echo "Building Telegram SSH Bot..."
|
|
5
|
+
|
|
6
|
+
# Clean previous builds
|
|
7
|
+
rm -rf dist build
|
|
8
|
+
|
|
9
|
+
# Compile TypeScript
|
|
10
|
+
echo "Compiling TypeScript..."
|
|
11
|
+
npm run build
|
|
12
|
+
|
|
13
|
+
# Create build directory
|
|
14
|
+
mkdir -p build
|
|
15
|
+
|
|
16
|
+
# Build binaries for current platform
|
|
17
|
+
echo "Creating binary executable..."
|
|
18
|
+
npx pkg . --targets node18-linux-x64 --output build/telegram-ssh-bot
|
|
19
|
+
|
|
20
|
+
echo "Build complete! Binary available at: build/telegram-ssh-bot"
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Post-install script for npm/pnpm global installation
|
|
4
|
+
* Sets up the .env configuration file if it doesn't exist
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { envFileExists, main } from "./setup-env.js";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Check if this is a global installation
|
|
11
|
+
* @returns {boolean} True if running as a global install
|
|
12
|
+
*/
|
|
13
|
+
function isGlobalInstall() {
|
|
14
|
+
// Check various npm config indicators for global install
|
|
15
|
+
const npmConfigGlobal = process.env.npm_config_global;
|
|
16
|
+
const npmPackageConfig = process.env.npm_package_config;
|
|
17
|
+
|
|
18
|
+
// npm_config_global is 'true' when installed with -g flag
|
|
19
|
+
if (npmConfigGlobal === "true") {
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Check if we're in a global node_modules directory
|
|
24
|
+
// This is a heuristic that works for most cases
|
|
25
|
+
const cwd = process.cwd();
|
|
26
|
+
if (
|
|
27
|
+
cwd.includes("node_modules") &&
|
|
28
|
+
(cwd.includes("/usr/local") ||
|
|
29
|
+
cwd.includes("/usr/lib") ||
|
|
30
|
+
cwd.includes("/lib/node_modules") ||
|
|
31
|
+
cwd.includes(".npm-global") ||
|
|
32
|
+
cwd.includes(".pnpm-global"))
|
|
33
|
+
) {
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Check for pnpm global install
|
|
38
|
+
if (
|
|
39
|
+
process.env.npm_config_user_agent &&
|
|
40
|
+
process.env.npm_config_user_agent.includes("pnpm")
|
|
41
|
+
) {
|
|
42
|
+
// pnpm sets different paths for global installs
|
|
43
|
+
if (cwd.includes("pnpm-global") || cwd.includes(".pnpm-global")) {
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Run the postinstall script
|
|
53
|
+
*/
|
|
54
|
+
function runPostinstall() {
|
|
55
|
+
// Only run for global installations
|
|
56
|
+
if (!isGlobalInstall()) {
|
|
57
|
+
console.log("Local installation detected. Skipping .env setup.");
|
|
58
|
+
console.log(
|
|
59
|
+
"For global installation, the .env file would be created at ~/.config/telegram-ssh-bot/.env",
|
|
60
|
+
);
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
console.log("Global installation detected. Setting up configuration...");
|
|
65
|
+
|
|
66
|
+
// Check if .env already exists
|
|
67
|
+
if (envFileExists()) {
|
|
68
|
+
console.log("Configuration file already exists. Skipping setup.");
|
|
69
|
+
console.log("Configuration location: ~/.config/telegram-ssh-bot/.env");
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Run the main setup function
|
|
74
|
+
const result = main({ generateKey: true, silent: false });
|
|
75
|
+
|
|
76
|
+
if (result.success) {
|
|
77
|
+
console.log("\nConfiguration setup complete!");
|
|
78
|
+
console.log(
|
|
79
|
+
'Run "telegram-ssh-bot" to start the bot after configuring your credentials.',
|
|
80
|
+
);
|
|
81
|
+
} else {
|
|
82
|
+
console.error("Configuration setup failed:", result.message);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Run the postinstall script
|
|
87
|
+
runPostinstall();
|