summaryrefslogtreecommitdiffstats
path: root/applications/luci-app-rustdesk-server/root/usr/share/rpcd/ucode/rustdesk-server.uc
blob: 184bb2f0b42ca70ee7e1f2fe16a43c476a7602dd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
#!/usr/bin/env ucode
'use strict';

import { popen, access, readfile, unlink } from 'fs';
import { process_list, init_enabled, init_action } from 'luci.sys';

const BIN_DIR = '/usr/bin';
const KEY_DIR = '/etc/rustdesk';

/*
 * Helper functions to reduce code duplication
 */

// Shell escape a string to prevent command injection
function shellquote(s) {
	return `'${replace(s, "'", "'\\''")}'`;
}

// Get PID of a process by name using luci.sys.process_list()
function getProcessPid(process_name) {
	for (let proc in process_list()) {
		if (index(proc.COMMAND, process_name) >= 0) {
			return proc.PID;
		}
	}
	return null;
}

// Execute a command and return trimmed output (for version queries only)
function execCommand(bin, args) {
	let result = null;
	let cmd = shellquote(bin) + ' ' + args;
	let pp = popen(cmd, 'r');
	if (pp) {
		let output = pp.read('all');
		pp.close();
		if (output) {
			result = trim(output);
		}
	}
	return result;
}

// Check if a file exists
function fileExists(path) {
	return !!access(path);
}

// Read file content and trim
function readFileContent(path) {
	let content = readfile(path);
	return content ? trim(content) : null;
}

// Safe file deletion
function safeUnlink(path) {
	return unlink(path) || false;
}

const methods = {
	get_status: {
		call: function() {
			// Check if service is enabled for boot using luci.sys.init_enabled()
			let boot_enabled = init_enabled('rustdesk-server');

			return {
				hbbs_pid: getProcessPid('hbbs'),
				hbbr_pid: getProcessPid('hbbr'),
				hbbs_exists: fileExists(BIN_DIR + '/hbbs'),
				hbbr_exists: fileExists(BIN_DIR + '/hbbr'),
				boot_enabled: boot_enabled
			};
		}
	},

	get_public_key: {
		call: function() {
			let key_path = KEY_DIR + '/id_ed25519.pub';
			let key_exists = fileExists(key_path);
			let public_key = null;

			if (key_exists) {
				public_key = readFileContent(key_path);
			}

			return {
				key_exists: key_exists,
				public_key: public_key,
				key_path: key_path
			};
		}
	},

	service_action: {
		args: { action: 'action' },
		call: function(req) {
			let action = '';

			if (req && req.args && req.args.action) {
				action = req.args.action;
			}

			// Validate action - whitelist approach
			const valid_actions = ['start', 'stop', 'restart', 'reload', 'enable', 'disable'];
			if (index(valid_actions, action) < 0) {
				return {
					success: false,
					error: 'Invalid action. Allowed: ' + join(', ', valid_actions)
				};
			}

			// Use luci.sys.init_action() for service control
			let result = init_action('rustdesk-server', action);

			return {
				success: (result === 0),
				action: action,
				exit_code: result
			};
		}
	},

	get_version: {
		call: function() {
			return {
				hbbs_version: fileExists(BIN_DIR + '/hbbs') ? execCommand(BIN_DIR + '/hbbs', '--version 2>&1') : null,
				hbbr_version: fileExists(BIN_DIR + '/hbbr') ? execCommand(BIN_DIR + '/hbbr', '--version 2>&1') : null
			};
		}
	},

	regenerate_key: {
		call: function() {
			let key_priv = KEY_DIR + '/id_ed25519';
			let key_pub = KEY_DIR + '/id_ed25519.pub';

			// Step 1: Stop the service first so keys are not in use
			// init_action is synchronous - waits for service to fully stop
			init_action('rustdesk-server', 'stop');

			// Step 2: Remove existing keys
			let priv_deleted = safeUnlink(key_priv);
			let pub_deleted = safeUnlink(key_pub);

			// Verify keys are deleted
			let keys_deleted = !fileExists(key_priv) && !fileExists(key_pub);

			// The UI will call restart to regenerate the keys
			// hbbs automatically generates new keys on startup if they don't exist

			return {
				success: keys_deleted,
				keys_deleted: keys_deleted,
				priv_deleted: priv_deleted,
				pub_deleted: pub_deleted,
				key_path: key_pub,
				message: keys_deleted ? 'Keys deleted. Restart service to generate new keys.' : 'Failed to delete keys'
			};
		}
	}
};

return { 'luci.rustdesk-server': methods };