[fix] Fixed a vmess import default value issue.

This commit is contained in:
Leroy.H.Y 2020-01-15 17:18:07 +08:00
parent d0621692e4
commit c286d25606
No known key found for this signature in database
GPG Key ID: 6AC1673B587DC37D
2 changed files with 55 additions and 28 deletions

View File

@ -1 +1 @@
2781 2786

View File

@ -112,12 +112,14 @@ namespace Qv2ray
// This generates global config containing only one outbound.... // This generates global config containing only one outbound....
CONFIGROOT ConvertConfigFromVMessString(const QString &vmess, QString *alias, QString *errMessage) CONFIGROOT ConvertConfigFromVMessString(const QString &vmess, QString *alias, QString *errMessage)
{ {
#define default CONFIGROOT()
LOG(MODULE_CONFIG, "Trying to convert from a vmess string.")
// Reset errMessage // Reset errMessage
*errMessage = ""; *errMessage = "";
if (!vmess.toLower().startsWith("vmess://")) { if (!vmess.toLower().startsWith("vmess://")) {
*errMessage = QObject::tr("VMess string should start with 'vmess://'"); *errMessage = QObject::tr("VMess string should start with 'vmess://'");
return CONFIGROOT(); return default;
} }
try { try {
@ -126,7 +128,7 @@ namespace Qv2ray
if (b64Str.isEmpty()) { if (b64Str.isEmpty()) {
*errMessage = QObject::tr("VMess string should be a valid base64 string"); *errMessage = QObject::tr("VMess string should be a valid base64 string");
return CONFIGROOT(); return default;
} }
auto vmessString = Base64Decode(b64Str); auto vmessString = Base64Decode(b64Str);
@ -134,23 +136,21 @@ namespace Qv2ray
if (!jsonErr.isEmpty()) { if (!jsonErr.isEmpty()) {
*errMessage = jsonErr; *errMessage = jsonErr;
return CONFIGROOT(); return default;
} }
auto vmessConf = JsonFromString(vmessString); auto vmessConf = JsonFromString(vmessString);
if (vmessConf.isEmpty()) { if (vmessConf.isEmpty()) {
*errMessage = QObject::tr("JSON should not be empty"); *errMessage = QObject::tr("JSON should not be empty");
return CONFIGROOT(); return default;
} }
bool flag = true;
// C is a quick hack... // C is a quick hack...
#define C(k) vmessConf.contains(k) #define C(k) vmessConf.contains(k)
bool flag = true; // id, aid, port and add are mandatory fields of a vmess:// link.
flag = flag && C("id"); flag = flag && C("id") && C("aid") && C("port") && C("add");
flag = flag && C("aid");
flag = flag && C("port");
flag = flag && C("add");
// Stream Settings // Stream Settings
auto net = C("net") ? vmessConf["net"].toString() : "tcp"; auto net = C("net") ? vmessConf["net"].toString() : "tcp";
@ -166,32 +166,58 @@ namespace Qv2ray
} catch (exception *e) { } catch (exception *e) {
LOG(MODULE_IMPORT, "Failed to decode vmess string: " + QString(e->what())) LOG(MODULE_IMPORT, "Failed to decode vmess string: " + QString(e->what()))
*errMessage = e->what(); *errMessage = e->what();
return CONFIGROOT(); return default;
} }
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
CONFIGROOT root; CONFIGROOT root;
QStringRef vmessJsonB64(&vmess, 8, vmess.length() - 8); auto b64String = QStringRef(&vmess, 8, vmess.length() - 8).toString();
auto vmessConf = JsonFromString(Base64Decode(vmessJsonB64.toString())); auto vmessConf = JsonFromString(Base64Decode(b64String));
// //
QString ps, add, id, net, type, host, path, tls; QString ps, add, id, net, type, host, path, tls;
int port, aid; int port, aid;
// //
ps = vmessConf.contains("ps") ? vmessConf["ps"].toVariant().toString() // key = key in JSON and the variable name.
: (vmessConf["add"].toVariant().toString() + ":" + vmessConf["port"].toVariant().toString()); // values = Candidate variable list, if not match, the first one is used as default.
add = vmessConf["add"].toVariant().toString(); // [[val.size() <= 1]] is used when only the default value exists.
id = vmessConf["id"].toVariant().toString(); // - It can be empty, if so, if the key is not in the JSON, or the value is empty, it'll report an error.
net = vmessConf.contains("net") ? vmessConf["net"].toVariant().toString() : "tcp"; // - Else if it contains one thing. if the key is not in the JSON, or the value is empty, it'll use that one.
type = vmessConf.contains("type") ? vmessConf["type"].toVariant().toString() : "none"; // - Else if it contains many things, when the key IS in the JSON but not in those THINGS, it'll use the first one in the THINGS
host = vmessConf["host"].toVariant().toString(); // - Else, it'll use the value found from the JSON object.
path = vmessConf["path"].toVariant().toString(); //
tls = vmessConf.contains("tls") ? vmessConf["tls"].toVariant().toString() : ""; #define empty_arg
#define __vmess_checker__func(key, values) \
{\
auto val = QStringList() values;\
if (vmessConf.contains(#key) && !vmessConf[#key].toVariant().toString().trimmed().isEmpty() \
&& (val.size() <= 1 || val.contains(vmessConf[#key].toVariant().toString()))) {\
key = vmessConf[#key].toVariant().toString();\
DEBUG(MODULE_IMPORT, "Found key \"" #key "\" within the vmess object.")\
} else if (val.size() == 1) {\
key = val.first(); \
DEBUG(MODULE_IMPORT, "Using key \"" #key "\" from the first candidate list.")\
} else{\
*errMessage = QObject::tr(#key " does not exist."); \
LOG(MODULE_IMPORT, "Cannot process \"" #key "\" since it's not included in the json object." ) \
LOG(MODULE_IMPORT, " --> values: " + Stringify(val) ) \
LOG(MODULE_IMPORT, " --> PS: " + ps) \
}\
}
// Strict check of VMess protocol, to check if the specified value is in the correct range.
//
// Get Alias (AKA ps) from address and port.
__vmess_checker__func(ps, << vmessConf["add"].toVariant().toString() + ":" + vmessConf["port"].toVariant().toString());
__vmess_checker__func(add, empty_arg)
__vmess_checker__func(id, empty_arg)
__vmess_checker__func(net, << "tcp" << "http" << "h2" << "ws" << "kcp" << "domainsocket" << "quic")
__vmess_checker__func(type, << "none" << "http" << "srtp" << "utp" << "wechat-video")
__vmess_checker__func(path, empty_arg)
__vmess_checker__func(host, empty_arg)
__vmess_checker__func(tls, << "")
// //
port = vmessConf["port"].toVariant().toInt(); port = vmessConf["port"].toVariant().toInt();
aid = vmessConf["aid"].toVariant().toInt(); aid = vmessConf["aid"].toVariant().type();
// // Apply the settings.
// More strict check could be implemented, such as to check if the specified value is
// in the currect format.
// //
// User // User
VMessServerObject::UserObject user; VMessServerObject::UserObject user;
@ -218,7 +244,7 @@ namespace Qv2ray
} else if (net == "http" || net == "h2") { } else if (net == "http" || net == "h2") {
// Fill hosts for HTTP // Fill hosts for HTTP
for (auto _host : host.split(',')) { for (auto _host : host.split(',')) {
streaming.httpSettings.host.push_back(_host); streaming.httpSettings.host.push_back(_host.trimmed());
} }
streaming.httpSettings.path = path; streaming.httpSettings.path = path;
@ -245,7 +271,8 @@ namespace Qv2ray
// //
root["outbounds"] = QJsonArray() << outbound; root["outbounds"] = QJsonArray() << outbound;
// If previous alias is empty, just the PS is needed, else, append a "_" // If previous alias is empty, just the PS is needed, else, append a "_"
*alias = alias->isEmpty() ? ps : *alias + "_" + ps; *alias = alias->trimmed().isEmpty() ? ps : *alias + "_" + ps;
#undef default
return root; return root;
} }