[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....
CONFIGROOT ConvertConfigFromVMessString(const QString &vmess, QString *alias, QString *errMessage)
{
#define default CONFIGROOT()
LOG(MODULE_CONFIG, "Trying to convert from a vmess string.")
// Reset errMessage
*errMessage = "";
if (!vmess.toLower().startsWith("vmess://")) {
*errMessage = QObject::tr("VMess string should start with 'vmess://'");
return CONFIGROOT();
return default;
}
try {
@ -126,7 +128,7 @@ namespace Qv2ray
if (b64Str.isEmpty()) {
*errMessage = QObject::tr("VMess string should be a valid base64 string");
return CONFIGROOT();
return default;
}
auto vmessString = Base64Decode(b64Str);
@ -134,23 +136,21 @@ namespace Qv2ray
if (!jsonErr.isEmpty()) {
*errMessage = jsonErr;
return CONFIGROOT();
return default;
}
auto vmessConf = JsonFromString(vmessString);
if (vmessConf.isEmpty()) {
*errMessage = QObject::tr("JSON should not be empty");
return CONFIGROOT();
return default;
}
bool flag = true;
// C is a quick hack...
#define C(k) vmessConf.contains(k)
bool flag = true;
flag = flag && C("id");
flag = flag && C("aid");
flag = flag && C("port");
flag = flag && C("add");
// id, aid, port and add are mandatory fields of a vmess:// link.
flag = flag && C("id") && C("aid") && C("port") && C("add");
// Stream Settings
auto net = C("net") ? vmessConf["net"].toString() : "tcp";
@ -166,32 +166,58 @@ namespace Qv2ray
} catch (exception *e) {
LOG(MODULE_IMPORT, "Failed to decode vmess string: " + QString(e->what()))
*errMessage = e->what();
return CONFIGROOT();
return default;
}
// --------------------------------------------------------------------------------------
CONFIGROOT root;
QStringRef vmessJsonB64(&vmess, 8, vmess.length() - 8);
auto vmessConf = JsonFromString(Base64Decode(vmessJsonB64.toString()));
auto b64String = QStringRef(&vmess, 8, vmess.length() - 8).toString();
auto vmessConf = JsonFromString(Base64Decode(b64String));
//
QString ps, add, id, net, type, host, path, tls;
int port, aid;
//
ps = vmessConf.contains("ps") ? vmessConf["ps"].toVariant().toString()
: (vmessConf["add"].toVariant().toString() + ":" + vmessConf["port"].toVariant().toString());
add = vmessConf["add"].toVariant().toString();
id = vmessConf["id"].toVariant().toString();
net = vmessConf.contains("net") ? vmessConf["net"].toVariant().toString() : "tcp";
type = vmessConf.contains("type") ? vmessConf["type"].toVariant().toString() : "none";
host = vmessConf["host"].toVariant().toString();
path = vmessConf["path"].toVariant().toString();
tls = vmessConf.contains("tls") ? vmessConf["tls"].toVariant().toString() : "";
// key = key in JSON and the variable name.
// values = Candidate variable list, if not match, the first one is used as default.
// [[val.size() <= 1]] is used when only the default value exists.
// - It can be empty, if so, if the key is not in the JSON, or the value is empty, it'll report an error.
// - Else if it contains one thing. if the key is not in the JSON, or the value is empty, it'll use that one.
// - 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
// - Else, it'll use the value found from the JSON object.
//
#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();
aid = vmessConf["aid"].toVariant().toInt();
//
// More strict check could be implemented, such as to check if the specified value is
// in the currect format.
aid = vmessConf["aid"].toVariant().type();
// Apply the settings.
//
// User
VMessServerObject::UserObject user;
@ -218,7 +244,7 @@ namespace Qv2ray
} else if (net == "http" || net == "h2") {
// Fill hosts for HTTP
for (auto _host : host.split(',')) {
streaming.httpSettings.host.push_back(_host);
streaming.httpSettings.host.push_back(_host.trimmed());
}
streaming.httpSettings.path = path;
@ -245,7 +271,8 @@ namespace Qv2ray
//
root["outbounds"] = QJsonArray() << outbound;
// 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;
}