Skip to content

Commit bf37f67

Browse files
committed
feat: add recommended install preset and input validation (#600)
Installer: - Add Recommended install type as default (VDD + firewall + autostart) - Add detailed en/zh component descriptions explaining each purpose - Reorder types: Recommended > Full > Compact > Custom Config validation (confighttp.cpp): - saveApp: validate app name length (1-256 chars) - saveConfig: validate sunshine_name and adapter_name length - savePassword: validate username (max 128) and password (max 256) - savePin: validate PIN format (4-8 numeric digits) and client name - unpair: validate UUID length (max 64)
1 parent d07498c commit bf37f67

2 files changed

Lines changed: 86 additions & 17 deletions

File tree

cmake/packaging/sunshine.iss.in

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,16 @@ english.ComponentFirewall=Add firewall exclusions
7474
english.ComponentGamepad=Virtual Gamepad (ViGEmBus)
7575
english.ComponentVmouse=Virtual Mouse Driver (UMDF)
7676
english.ComponentTools=Diagnostic tools (dxgi-info, audio-info)
77-
english.TypeFull=Full installation
78-
english.TypeCompact=Compact installation
77+
english.TypeRecommended=Recommended (virtual display + firewall + autostart)
78+
english.TypeFull=Full installation (all components)
79+
english.TypeCompact=Compact installation (core only)
7980
english.TypeCustom=Custom installation
81+
english.ComponentVDDDesc=Required for headless/remote streaming without a physical monitor. Enables HDR passthrough.
82+
english.ComponentFirewallDesc=Allows Moonlight clients to discover and connect to this PC over the network.
83+
english.ComponentAutostartDesc=Sunshine will start automatically when Windows boots. Recommended for always-on streaming.
84+
english.ComponentGamepadDesc=Emulates Xbox controller for games. Install only if you need gamepad input from the client.
85+
english.ComponentVmouseDesc=Provides smooth absolute mouse positioning. Install if cursor feels laggy.
86+
english.ComponentToolsDesc=dxgi-info, audio-info for troubleshooting display and audio issues.
8087
english.StatusResetPermissions=Resetting file permissions...
8188
english.StatusUpdatePath=Updating system PATH...
8289
english.StatusMigrateConfig=Migrating configuration files...
@@ -104,9 +111,16 @@ chinesesimplified.ComponentFirewall=添加防火墙规则
104111
chinesesimplified.ComponentGamepad=虚拟手柄(ViGEmBus)
105112
chinesesimplified.ComponentVmouse=虚拟鼠标驱动(UMDF)
106113
chinesesimplified.ComponentTools=诊断工具(dxgi-info、audio-info)
107-
chinesesimplified.TypeFull=完全安装
108-
chinesesimplified.TypeCompact=简洁安装
114+
chinesesimplified.TypeRecommended=推荐安装(虚拟显示器 + 防火墙 + 开机自启)
115+
chinesesimplified.TypeFull=完全安装(所有组件)
116+
chinesesimplified.TypeCompact=简洁安装(仅核心)
109117
chinesesimplified.TypeCustom=自定义安装
118+
chinesesimplified.ComponentVDDDesc=无头/远程串流必装。无需外接显示器即可串流,支持 HDR 直通。
119+
chinesesimplified.ComponentFirewallDesc=允许 Moonlight 客户端通过网络发现并连接本机。
120+
chinesesimplified.ComponentAutostartDesc=Windows 启动时自动运行 Sunshine。推荐常驻串流使用。
121+
chinesesimplified.ComponentGamepadDesc=模拟 Xbox 手柄。仅需要从客户端传入手柄输入时安装。
122+
chinesesimplified.ComponentVmouseDesc=提供平滑的绝对定位鼠标。如鼠标延迟可尝试安装。
123+
chinesesimplified.ComponentToolsDesc=dxgi-info、audio-info 等,用于排查显示和音频问题。
110124
chinesesimplified.StatusResetPermissions=正在重置文件权限...
111125
chinesesimplified.StatusUpdatePath=正在更新系统 PATH...
112126
chinesesimplified.StatusMigrateConfig=正在迁移配置文件...
@@ -126,19 +140,20 @@ chinesesimplified.StatusStoppingService=正在停止 Sunshine 服务...
126140
chinesesimplified.StatusStoppingProcesses=正在停止 Sunshine 进程...
127141

128142
[Types]
143+
Name: "recommended"; Description: "{cm:TypeRecommended}"
129144
Name: "full"; Description: "{cm:TypeFull}"
130145
Name: "compact"; Description: "{cm:TypeCompact}"
131146
Name: "custom"; Description: "{cm:TypeCustom}"; Flags: iscustom
132147

133148
[Components]
134-
Name: "application"; Description: "{cm:ComponentApplication}"; Types: full compact custom; Flags: fixed
135-
Name: "assets"; Description: "{cm:ComponentAssets}"; Types: full compact custom; Flags: fixed
136-
Name: "vdd"; Description: "{cm:ComponentVDD}"; Types: full
137-
Name: "autostart"; Description: "{cm:ComponentAutostart}"; Types: full
138-
Name: "firewall"; Description: "{cm:ComponentFirewall}"; Types: full compact
139-
Name: "gamepad"; Description: "{cm:ComponentGamepad}"; Types: full
140-
Name: "vmouse"; Description: "{cm:ComponentVmouse}"; Types: full
141-
Name: "tools"; Description: "{cm:ComponentTools}"; Types: full
149+
Name: "application"; Description: "{cm:ComponentApplication}"; Types: recommended full compact custom; Flags: fixed
150+
Name: "assets"; Description: "{cm:ComponentAssets}"; Types: recommended full compact custom; Flags: fixed
151+
Name: "vdd"; Description: "{cm:ComponentVDD} — {cm:ComponentVDDDesc}"; Types: recommended full; ExtraDiskSpaceRequired: 2097152
152+
Name: "firewall"; Description: "{cm:ComponentFirewall} — {cm:ComponentFirewallDesc}"; Types: recommended full compact
153+
Name: "autostart"; Description: "{cm:ComponentAutostart} — {cm:ComponentAutostartDesc}"; Types: recommended full
154+
Name: "gamepad"; Description: "{cm:ComponentGamepad} — {cm:ComponentGamepadDesc}"; Types: full
155+
Name: "vmouse"; Description: "{cm:ComponentVmouse} — {cm:ComponentVmouseDesc}"; Types: full
156+
Name: "tools"; Description: "{cm:ComponentTools} — {cm:ComponentToolsDesc}"; Types: full
142157

143158
[Tasks]
144159
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"

src/confighttp.cpp

Lines changed: 59 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <filesystem>
1212
#include <fstream>
1313
#include <iomanip>
14+
#include <algorithm>
1415
#include <atomic>
1516
#include <mutex>
1617
#include <stdexcept>
@@ -757,14 +758,23 @@ namespace confighttp {
757758
pt::ptree inputTree, fileTree;
758759

759760
try {
760-
// TODO: Input Validation
761761
pt::read_json(ss, inputTree);
762762
pt::read_json(config::stream.file_apps, fileTree);
763763

764764
auto &apps_node = fileTree.get_child("apps"s);
765765
auto &input_apps_node = inputTree.get_child("apps"s);
766766
auto &input_edit_node = inputTree.get_child("editApp"s);
767767

768+
// Validate app name when editing a specific app
769+
if (!input_edit_node.empty()) {
770+
auto app_name = input_edit_node.get<std::string>("name", "");
771+
if (app_name.empty() || app_name.size() > 256) {
772+
outputTree.put("status", "false");
773+
outputTree.put("error", "App name must be 1-256 characters");
774+
return;
775+
}
776+
}
777+
768778
if (input_edit_node.empty()) {
769779
fileTree.erase("apps");
770780
fileTree.push_back(std::make_pair("apps", input_apps_node));
@@ -1163,12 +1173,24 @@ namespace confighttp {
11631173
pt::ptree inputTree;
11641174

11651175
try {
1166-
// TODO: Input Validation
11671176
pt::read_json(ss, inputTree);
11681177
std::string resArray = inputTree.get<std::string>("resolutions", "[]");
11691178
std::string fpsArray = inputTree.get<std::string>("fps", "[]");
11701179
std::string gpu_name = inputTree.get<std::string>("adapter_name", "");
11711180

1181+
// Validate config field lengths to prevent abuse
1182+
auto sunshine_name = inputTree.get<std::string>("sunshine_name", "");
1183+
if (sunshine_name.size() > 256) {
1184+
outputTree.put("status", "false");
1185+
outputTree.put("error", "sunshine_name too long (max 256)");
1186+
return;
1187+
}
1188+
if (gpu_name.size() > 256) {
1189+
outputTree.put("status", "false");
1190+
outputTree.put("error", "adapter_name too long (max 256)");
1191+
return;
1192+
}
1193+
11721194
saveVddSettings(resArray, fpsArray, gpu_name);
11731195

11741196
// 将 inputTree 转换为 std::map(保证有序)
@@ -1249,13 +1271,25 @@ namespace confighttp {
12491271
});
12501272

12511273
try {
1252-
// TODO: Input Validation
12531274
pt::read_json(ss, inputTree);
12541275
auto username = inputTree.count("currentUsername") > 0 ? inputTree.get<std::string>("currentUsername") : "";
12551276
auto newUsername = inputTree.get<std::string>("newUsername");
12561277
auto password = inputTree.count("currentPassword") > 0 ? inputTree.get<std::string>("currentPassword") : "";
12571278
auto newPassword = inputTree.count("newPassword") > 0 ? inputTree.get<std::string>("newPassword") : "";
12581279
auto confirmPassword = inputTree.count("confirmNewPassword") > 0 ? inputTree.get<std::string>("confirmNewPassword") : "";
1280+
1281+
// Validate credential lengths
1282+
if (newUsername.size() > 128) {
1283+
outputTree.put("status", false);
1284+
outputTree.put("error", "Username too long (max 128)");
1285+
return;
1286+
}
1287+
if (newPassword.size() > 256) {
1288+
outputTree.put("status", false);
1289+
outputTree.put("error", "Password too long (max 256)");
1290+
return;
1291+
}
1292+
12591293
if (newUsername.length() == 0) newUsername = username;
12601294
if (newUsername.length() == 0) {
12611295
outputTree.put("status", false);
@@ -1306,10 +1340,23 @@ namespace confighttp {
13061340
});
13071341

13081342
try {
1309-
// TODO: Input Validation
13101343
pt::read_json(ss, inputTree);
13111344
std::string pin = inputTree.get<std::string>("pin");
13121345
std::string name = inputTree.get<std::string>("name");
1346+
1347+
// Validate PIN: must be numeric digits only, 4-8 characters
1348+
if (pin.size() < 4 || pin.size() > 8 || !std::all_of(pin.begin(), pin.end(), ::isdigit)) {
1349+
outputTree.put("status", false);
1350+
outputTree.put("error", "PIN must be 4-8 digits");
1351+
return;
1352+
}
1353+
// Validate client name
1354+
if (name.empty() || name.size() > 256) {
1355+
outputTree.put("status", false);
1356+
outputTree.put("error", "Client name must be 1-256 characters");
1357+
return;
1358+
}
1359+
13131360
bool pin_result = nvhttp::pin(pin, name);
13141361
outputTree.put("status", pin_result);
13151362

@@ -1528,9 +1575,16 @@ namespace confighttp {
15281575
});
15291576

15301577
try {
1531-
// TODO: Input Validation
15321578
pt::read_json(ss, inputTree);
15331579
std::string uuid = inputTree.get<std::string>("uuid");
1580+
1581+
// Validate UUID format (hex + hyphens, reasonable length)
1582+
if (uuid.empty() || uuid.size() > 64) {
1583+
outputTree.put("status", false);
1584+
outputTree.put("error", "Invalid client UUID");
1585+
return;
1586+
}
1587+
15341588
outputTree.put("status", nvhttp::unpair_client(uuid));
15351589
}
15361590
catch (std::exception &e) {

0 commit comments

Comments
 (0)