Skip to content

Commit d6fd4aa

Browse files
committed
Fix password parsing for SS2022 with special characters
- Add `splitKeyValue()` function to split only at first separator - Replace `split()` with `splitKeyValue()` for config key-value parsing - Prevent truncation of password fields containing `=` Fixes #838
1 parent 8e042ae commit d6fd4aa

File tree

3 files changed

+49
-19
lines changed

3 files changed

+49
-19
lines changed

src/parser/subparser.cpp

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ void hysteriaConstruct(
168168
if (!up.empty())
169169
{
170170
if (up.length() > 4 && up.find("bps") == up.length() - 3)
171-
171+
172172
node.Up = up;
173173
else if (to_int(up))
174174
{
@@ -209,13 +209,13 @@ void hysteriaConstruct(
209209
}
210210

211211
void hysteria2Construct(
212-
Proxy &node,
212+
Proxy &node,
213213
const std::string &group,
214214
const std::string &remarks,
215-
const std::string &server,
215+
const std::string &server,
216216
const std::string &port,
217217
const std::string &ports,
218-
const std::string &up,
218+
const std::string &up,
219219
const std::string &down,
220220
const std::string &password,
221221
const std::string &obfs,
@@ -226,9 +226,9 @@ void hysteria2Construct(
226226
const std::string &ca,
227227
const std::string &caStr,
228228
const std::string &cwnd,
229-
const std::string &hop_interval,
230-
tribool tfo,
231-
tribool scv,
229+
const std::string &hop_interval,
230+
tribool tfo,
231+
tribool scv,
232232
const std::string &underlying_proxy
233233
) {
234234
commonConstruct(node, ProxyType::Hysteria2, group, remarks, server, port, tribool(), tfo, scv, tribool(), underlying_proxy);
@@ -1352,7 +1352,7 @@ void explodeClash(Node yamlnode, std::vector<Proxy> &nodes)
13521352
singleproxy["down"] >>= down;
13531353
singleproxy["password"] >>= password;
13541354
if (password.empty())
1355-
singleproxy["auth"] >>= password;
1355+
singleproxy["auth"] >>= password;
13561356
singleproxy["obfs"] >>= obfs;
13571357
singleproxy["obfs-password"] >>= obfs_password;
13581358
singleproxy["sni"] >>= sni;
@@ -1728,7 +1728,7 @@ bool explodeSurge(std::string surge, std::vector<Proxy> &nodes)
17281728

17291729
for(i = 3; i < configs.size(); i++)
17301730
{
1731-
vArray = split(configs[i], "=");
1731+
vArray = splitKeyValue(configs[i], "=");
17321732
if(vArray.size() < 2)
17331733
continue;
17341734
itemName = trim(vArray[0]);
@@ -1778,7 +1778,7 @@ bool explodeSurge(std::string surge, std::vector<Proxy> &nodes)
17781778
}
17791779
for(i = 5; i < configs.size(); i++)
17801780
{
1781-
vArray = split(configs[i], "=");
1781+
vArray = splitKeyValue(configs[i], "=");
17821782
if(vArray.size() < 2)
17831783
continue;
17841784
itemName = trim(vArray[0]);
@@ -1810,7 +1810,7 @@ bool explodeSurge(std::string surge, std::vector<Proxy> &nodes)
18101810

18111811
for(i = 3; i < configs.size(); i++)
18121812
{
1813-
vArray = split(configs[i], "=");
1813+
vArray = splitKeyValue(configs[i], "=");
18141814
if(vArray.size() != 2)
18151815
continue;
18161816
itemName = trim(vArray[0]);
@@ -1873,7 +1873,7 @@ bool explodeSurge(std::string surge, std::vector<Proxy> &nodes)
18731873
continue;
18741874
for(i = 3; i < configs.size(); i++)
18751875
{
1876-
vArray = split(configs[i], "=");
1876+
vArray = splitKeyValue(configs[i], "=");
18771877
if(vArray.size() < 2)
18781878
continue;
18791879
itemName = trim(vArray[0]);
@@ -1903,7 +1903,7 @@ bool explodeSurge(std::string surge, std::vector<Proxy> &nodes)
19031903

19041904
for(i = 3; i < configs.size(); i++)
19051905
{
1906-
vArray = split(configs[i], "=");
1906+
vArray = splitKeyValue(configs[i], "=");
19071907
if(vArray.size() != 2)
19081908
continue;
19091909
itemName = trim(vArray[0]);
@@ -1940,7 +1940,7 @@ bool explodeSurge(std::string surge, std::vector<Proxy> &nodes)
19401940

19411941
for(i = 3; i < configs.size(); i++)
19421942
{
1943-
vArray = split(configs[i], "=");
1943+
vArray = splitKeyValue(configs[i], "=");
19441944
if(vArray.size() != 2)
19451945
continue;
19461946
itemName = trim(vArray[0]);
@@ -1978,7 +1978,7 @@ bool explodeSurge(std::string surge, std::vector<Proxy> &nodes)
19781978
case "wireguard"_hash:
19791979
for (i = 1; i < configs.size(); i++)
19801980
{
1981-
vArray = split(trim(configs[i]), "=");
1981+
vArray = splitKeyValue(trim(configs[i]), "=");
19821982
if(vArray.size() != 2)
19831983
continue;
19841984
itemName = trim(vArray[0]);
@@ -2045,7 +2045,7 @@ bool explodeSurge(std::string surge, std::vector<Proxy> &nodes)
20452045

20462046
for(i = 1; i < configs.size(); i++)
20472047
{
2048-
vArray = split(trim(configs[i]), "=");
2048+
vArray = splitKeyValue(trim(configs[i]), "=");
20492049
if(vArray.size() != 2)
20502050
continue;
20512051
itemName = trim(vArray[0]);
@@ -2146,7 +2146,7 @@ bool explodeSurge(std::string surge, std::vector<Proxy> &nodes)
21462146

21472147
for(i = 1; i < configs.size(); i++)
21482148
{
2149-
vArray = split(trim(configs[i]), "=");
2149+
vArray = splitKeyValue(trim(configs[i]), "=");
21502150
if(vArray.size() != 2)
21512151
continue;
21522152
itemName = trim(vArray[0]);
@@ -2214,7 +2214,7 @@ bool explodeSurge(std::string surge, std::vector<Proxy> &nodes)
22142214

22152215
for(i = 1; i < configs.size(); i++)
22162216
{
2217-
vArray = split(trim(configs[i]), "=");
2217+
vArray = splitKeyValue(trim(configs[i]), "=");
22182218
if(vArray.size() != 2)
22192219
continue;
22202220
itemName = trim(vArray[0]);
@@ -2262,7 +2262,7 @@ bool explodeSurge(std::string surge, std::vector<Proxy> &nodes)
22622262

22632263
for(i = 1; i < configs.size(); i++)
22642264
{
2265-
vArray = split(trim(configs[i]), "=");
2265+
vArray = splitKeyValue(trim(configs[i]), "=");
22662266
if(vArray.size() != 2)
22672267
continue;
22682268
itemName = trim(vArray[0]);

src/utils/string.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,34 @@ std::vector<std::string_view> split(std::string_view s, char separator)
4545
return result;
4646
}
4747

48+
/**
49+
* Split string at the first occurrence of separator only.
50+
*
51+
* This function is designed for parsing key-value pairs where the value
52+
* may contain the separator character. For example, in SS2022 protocol,
53+
* the password field may contain '=' characters that should not be treated
54+
* as additional separators.
55+
*/
56+
std::vector<std::string> splitKeyValue(const std::string &s, const std::string &separator)
57+
{
58+
std::vector<std::string> result;
59+
string_size pos = s.find(separator);
60+
61+
if (pos == std::string::npos)
62+
{
63+
// No separator found, return the whole string
64+
result.push_back(s);
65+
}
66+
else
67+
{
68+
// Split only at the first occurrence of separator
69+
result.push_back(s.substr(0, pos));
70+
result.push_back(s.substr(pos + separator.size()));
71+
}
72+
73+
return result;
74+
}
75+
4876
std::string UTF8ToCodePoint(const std::string &data)
4977
{
5078
std::stringstream ss;

src/utils/string.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ using string_pair_array = std::vector<std::pair<std::string, std::string>>;
1818
std::vector<std::string> split(const std::string &s, const std::string &separator);
1919
std::vector<std::string_view> split(std::string_view s, char separator);
2020
void split(std::vector<std::string_view> &result, std::string_view s, char separator);
21+
// Split string at first separator only, useful for key-value pairs where value may contain separator
22+
std::vector<std::string> splitKeyValue(const std::string &s, const std::string &separator);
2123
std::string join(const string_array &arr, const std::string &delimiter);
2224

2325
template <typename InputIt>

0 commit comments

Comments
 (0)