mirror of
https://github.com/MetaCubeX/subconverter.git
synced 2025-11-04 18:19:42 +08:00
Enhancements
Add SNI host parsing support for Trojan subscriptions. Add detailed log report. Optimize codes. Update build scripts.
This commit is contained in:
parent
4cee6b5a5e
commit
ef8b4e39ef
@ -48,6 +48,7 @@ ADD_EXECUTABLE(subconverter
|
||||
src/speedtestutil.cpp
|
||||
src/subexport.cpp
|
||||
src/templates.cpp
|
||||
src/upload.cpp
|
||||
src/webget.cpp
|
||||
src/webserver_libevent.cpp)
|
||||
INCLUDE_DIRECTORIES(src)
|
||||
|
||||
@ -12,6 +12,7 @@ c++ -std=c++17 -Wall -fexceptions -c src/nodemanip.cpp -o obj/nodemanip.o
|
||||
c++ -std=c++17 -Wall -fexceptions -c src/rapidjson_extra.cpp -o obj/rapidjson_extra.o
|
||||
c++ -std=c++17 -Wall -fexceptions -c src/speedtestutil.cpp -o obj/speedtestutil.o
|
||||
c++ -std=c++17 -Wall -fexceptions -c src/subexport.cpp -o obj/subexport.o
|
||||
c++ -std=c++17 -Wall -fexceptions -c src/upload.cpp -o obj/upload.o
|
||||
c++ -std=c++17 -Wall -fexceptions -c src/templates.cpp -o obj/templates.o
|
||||
c++ -std=c++17 -Wall -fexceptions -c src/webget.cpp -o obj/webget.o
|
||||
c++ -std=c++17 -Wall -fexceptions -c src/webserver_libevent.cpp -o obj/webserver_libevent.o
|
||||
|
||||
@ -18,6 +18,7 @@
|
||||
#include "logger.h"
|
||||
#include "string_hash.h"
|
||||
#include "templates.h"
|
||||
#include "upload.h"
|
||||
|
||||
//common settings
|
||||
std::string pref_path = "pref.ini", def_ext_config;
|
||||
@ -1580,6 +1581,7 @@ std::string surgeConfToClash(RESPONSE_CALLBACK_ARGS)
|
||||
*status_code = 400;
|
||||
return "Please insert your subscription link instead of clicking the default link.";
|
||||
}
|
||||
writeLog(0, "SurgeConfToClash called with url '" + url + "'.", LOG_LEVEL_INFO);
|
||||
|
||||
std::string proxy = parseProxy(proxy_config);
|
||||
YAML::Node clash;
|
||||
@ -1758,6 +1760,7 @@ std::string surgeConfToClash(RESPONSE_CALLBACK_ARGS)
|
||||
}
|
||||
clash[rule_name] = rule;
|
||||
|
||||
writeLog(0, "Conversion completed.", LOG_LEVEL_INFO);
|
||||
return YAML::Dump(clash);
|
||||
}
|
||||
|
||||
@ -1917,12 +1920,14 @@ std::string parseHostname(inja::Arguments &args)
|
||||
std::string template_webGet(inja::Arguments &args)
|
||||
{
|
||||
std::string data = args.at(0)->get<std::string>(), proxy = parseProxy(proxy_config);
|
||||
writeLog(0, "Template called fetch with url '" + data + "'.", LOG_LEVEL_INFO);
|
||||
return webGet(data, proxy, cache_config);
|
||||
}
|
||||
|
||||
std::string jinja2_webGet(const std::string &url)
|
||||
{
|
||||
std::string proxy = parseProxy(proxy_config);
|
||||
writeLog(0, "Template called fetch with url '" + url + "'.", LOG_LEVEL_INFO);
|
||||
return webGet(url, proxy, cache_config);
|
||||
}
|
||||
|
||||
@ -2097,6 +2102,7 @@ int simpleGenerator()
|
||||
std::string renderTemplate(RESPONSE_CALLBACK_ARGS)
|
||||
{
|
||||
std::string path = UrlDecode(getUrlArg(argument, "path"));
|
||||
writeLog(0, "Trying to render template '" + path + "'...", LOG_LEVEL_INFO);
|
||||
|
||||
if(path.find(template_path) != 0)
|
||||
{
|
||||
@ -2132,6 +2138,12 @@ std::string renderTemplate(RESPONSE_CALLBACK_ARGS)
|
||||
|
||||
std::string output_content;
|
||||
if(render_template(template_content, tpl_args, output_content, template_path) != 0)
|
||||
{
|
||||
*status_code = 400;
|
||||
writeLog(0, "Render failed with error.", LOG_LEVEL_WARNING);
|
||||
}
|
||||
else
|
||||
writeLog(0, "Render completed.", LOG_LEVEL_INFO);
|
||||
|
||||
return output_content;
|
||||
}
|
||||
|
||||
@ -733,7 +733,7 @@ void explodeHTTPSub(std::string link, const std::string &custom_port, nodeInfo &
|
||||
|
||||
void explodeTrojan(std::string trojan, const std::string &custom_port, int local_port, nodeInfo &node)
|
||||
{
|
||||
std::string server, port, psk, addition, remark;
|
||||
std::string server, port, psk, addition, remark, host;
|
||||
string_array vArray;
|
||||
trojan.erase(0, 9);
|
||||
string_size pos = trojan.rfind("#");
|
||||
@ -759,15 +759,19 @@ void explodeTrojan(std::string trojan, const std::string &custom_port, int local
|
||||
server = vArray[1];
|
||||
port = custom_port.empty() ? vArray[2] : custom_port;
|
||||
|
||||
host = getUrlArg(addition, "peer");
|
||||
|
||||
if(remark.empty())
|
||||
remark = server + ":" + port;
|
||||
if(host.empty() && !isIPv4(server) && !isIPv6(server))
|
||||
host = server;
|
||||
|
||||
node.linkType = SPEEDTEST_MESSAGE_FOUNDTROJAN;
|
||||
node.group = TROJAN_DEFAULT_GROUP;
|
||||
node.remarks = remark;
|
||||
node.server = server;
|
||||
node.port = to_int(port, 0);
|
||||
node.proxyStr = trojanConstruct(remark, server, port, psk, "", false);
|
||||
node.proxyStr = trojanConstruct(remark, server, port, psk, host, true);
|
||||
}
|
||||
|
||||
void explodeQuan(std::string quan, const std::string &custom_port, int local_port, nodeInfo &node)
|
||||
|
||||
@ -583,7 +583,6 @@ void rulesetToSurge(INIReader &base_rule, std::vector<ruleset_content> &ruleset_
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const std::string rule_match_regex = "^(.*?,.*?)(,.*)(,.*)$";
|
||||
|
||||
for(ruleset_content &x : ruleset_content_array)
|
||||
@ -2678,113 +2677,3 @@ std::string netchToLoon(std::vector<nodeInfo> &nodes, std::string &base_conf, st
|
||||
|
||||
return ini.ToString();
|
||||
}
|
||||
|
||||
std::string buildGistData(std::string name, std::string content)
|
||||
{
|
||||
rapidjson::StringBuffer sb;
|
||||
rapidjson::Writer<rapidjson::StringBuffer> writer(sb);
|
||||
writer.StartObject();
|
||||
writer.Key("description");
|
||||
writer.String("subconverter");
|
||||
writer.Key("public");
|
||||
writer.Bool(false);
|
||||
writer.Key("files");
|
||||
writer.StartObject();
|
||||
writer.Key(name.data());
|
||||
writer.StartObject();
|
||||
writer.Key("content");
|
||||
writer.String(content.data());
|
||||
writer.EndObject();
|
||||
writer.EndObject();
|
||||
writer.EndObject();
|
||||
return sb.GetString();
|
||||
}
|
||||
|
||||
int uploadGist(std::string name, std::string path, std::string content, bool writeManageURL)
|
||||
{
|
||||
INIReader ini;
|
||||
rapidjson::Document json;
|
||||
std::string token, id, username, retData, url;
|
||||
int retVal = 0;
|
||||
|
||||
if(!fileExist("gistconf.ini"))
|
||||
{
|
||||
//std::cerr<<"gistconf.ini not found. Skipping...\n";
|
||||
writeLog(0, "gistconf.ini not found. Skipping...", LOG_LEVEL_ERROR);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ini.ParseFile("gistconf.ini");
|
||||
if(ini.EnterSection("common") != 0)
|
||||
{
|
||||
//std::cerr<<"gistconf.ini has incorrect format. Skipping...\n";
|
||||
writeLog(0, "gistconf.ini has incorrect format. Skipping...", LOG_LEVEL_ERROR);
|
||||
return -1;
|
||||
}
|
||||
|
||||
token = ini.Get("token");
|
||||
if(!token.size())
|
||||
{
|
||||
//std::cerr<<"No token is provided. Skipping...\n";
|
||||
writeLog(0, "No token is provided. Skipping...", LOG_LEVEL_ERROR);
|
||||
return -1;
|
||||
}
|
||||
|
||||
id = ini.Get("id");
|
||||
username = ini.Get("username");
|
||||
if(!path.size())
|
||||
{
|
||||
if(ini.ItemExist("path"))
|
||||
path = ini.Get(name, "path");
|
||||
else
|
||||
path = name;
|
||||
}
|
||||
|
||||
if(!id.size())
|
||||
{
|
||||
//std::cerr<<"No gist id is provided. Creating new gist...\n";
|
||||
writeLog(0, "No Gist id is provided. Creating new Gist...", LOG_LEVEL_ERROR);
|
||||
retVal = webPost("https://api.github.com/gists", buildGistData(path, content), getSystemProxy(), token, &retData);
|
||||
if(retVal != 201)
|
||||
{
|
||||
//std::cerr<<"Create new Gist failed! Return data:\n"<<retData<<"\n";
|
||||
writeLog(0, "Create new Gist failed! Return data:\n" + retData, LOG_LEVEL_ERROR);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
url = "https://gist.githubusercontent.com/" + username + "/" + id + "/raw/" + path;
|
||||
//std::cerr<<"Gist id provided. Modifying Gist...\n";
|
||||
writeLog(0, "Gist id provided. Modifying Gist...", LOG_LEVEL_INFO);
|
||||
if(writeManageURL)
|
||||
content = "#!MANAGED-CONFIG " + url + "\n" + content;
|
||||
retVal = webPatch("https://api.github.com/gists/" + id, buildGistData(path, content), getSystemProxy(), token, &retData);
|
||||
if(retVal != 200)
|
||||
{
|
||||
//std::cerr<<"Modify gist failed! Return data:\n"<<retData<<"\n";
|
||||
writeLog(0, "Modify Gist failed! Return data:\n" + retData, LOG_LEVEL_ERROR);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
json.Parse(retData.data());
|
||||
GetMember(json, "id", id);
|
||||
if(json.HasMember("owner"))
|
||||
GetMember(json["owner"], "login", username);
|
||||
url = "https://gist.githubusercontent.com/" + username + "/" + id + "/raw/" + path;
|
||||
//std::cerr<<"Writing to Gist success!\nGenerator: "<<name<<"\nPath: "<<path<<"\nRaw URL: "<<url<<"\nGist owner: "<<username<<"\n";
|
||||
writeLog(0, "Writing to Gist success!\nGenerator: " + name + "\nPath: " + path + "\nRaw URL: " + url + "\nGist owner: " + username, LOG_LEVEL_INFO);
|
||||
|
||||
ini.EraseSection();
|
||||
ini.Set("token", token);
|
||||
ini.Set("id", id);
|
||||
ini.Set("username", username);
|
||||
|
||||
ini.SetCurrentSection(path);
|
||||
ini.EraseSection();
|
||||
ini.Set("type", name);
|
||||
ini.Set("url", url);
|
||||
|
||||
ini.ToFile("gistconf.ini");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -58,7 +58,4 @@ std::string netchToQuan(std::vector<nodeInfo> &nodes, std::string &base_conf, st
|
||||
void netchToQuan(std::vector<nodeInfo> &nodes, INIReader &ini, std::vector<ruleset_content> &ruleset_content_array, string_array &extra_proxy_group, extra_settings &ext);
|
||||
std::string netchToSSD(std::vector<nodeInfo> &nodes, std::string &group, std::string &userinfo, extra_settings &ext);
|
||||
|
||||
std::string buildGistData(std::string name, std::string content);
|
||||
int uploadGist(std::string name, std::string path, std::string content, bool writeManageURL);
|
||||
|
||||
#endif // SUBEXPORT_H_INCLUDED
|
||||
|
||||
119
src/upload.cpp
Normal file
119
src/upload.cpp
Normal file
@ -0,0 +1,119 @@
|
||||
#include <string>
|
||||
|
||||
#include <rapidjson/writer.h>
|
||||
#include <rapidjson/document.h>
|
||||
|
||||
#include "webget.h"
|
||||
#include "ini_reader.h"
|
||||
#include "logger.h"
|
||||
#include "rapidjson_extra.h"
|
||||
|
||||
std::string buildGistData(std::string name, std::string content)
|
||||
{
|
||||
rapidjson::StringBuffer sb;
|
||||
rapidjson::Writer<rapidjson::StringBuffer> writer(sb);
|
||||
writer.StartObject();
|
||||
writer.Key("description");
|
||||
writer.String("subconverter");
|
||||
writer.Key("public");
|
||||
writer.Bool(false);
|
||||
writer.Key("files");
|
||||
writer.StartObject();
|
||||
writer.Key(name.data());
|
||||
writer.StartObject();
|
||||
writer.Key("content");
|
||||
writer.String(content.data());
|
||||
writer.EndObject();
|
||||
writer.EndObject();
|
||||
writer.EndObject();
|
||||
return sb.GetString();
|
||||
}
|
||||
|
||||
int uploadGist(std::string name, std::string path, std::string content, bool writeManageURL)
|
||||
{
|
||||
INIReader ini;
|
||||
rapidjson::Document json;
|
||||
std::string token, id, username, retData, url;
|
||||
int retVal = 0;
|
||||
|
||||
if(!fileExist("gistconf.ini"))
|
||||
{
|
||||
//std::cerr<<"gistconf.ini not found. Skipping...\n";
|
||||
writeLog(0, "gistconf.ini not found. Skipping...", LOG_LEVEL_ERROR);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ini.ParseFile("gistconf.ini");
|
||||
if(ini.EnterSection("common") != 0)
|
||||
{
|
||||
//std::cerr<<"gistconf.ini has incorrect format. Skipping...\n";
|
||||
writeLog(0, "gistconf.ini has incorrect format. Skipping...", LOG_LEVEL_ERROR);
|
||||
return -1;
|
||||
}
|
||||
|
||||
token = ini.Get("token");
|
||||
if(!token.size())
|
||||
{
|
||||
//std::cerr<<"No token is provided. Skipping...\n";
|
||||
writeLog(0, "No token is provided. Skipping...", LOG_LEVEL_ERROR);
|
||||
return -1;
|
||||
}
|
||||
|
||||
id = ini.Get("id");
|
||||
username = ini.Get("username");
|
||||
if(!path.size())
|
||||
{
|
||||
if(ini.ItemExist("path"))
|
||||
path = ini.Get(name, "path");
|
||||
else
|
||||
path = name;
|
||||
}
|
||||
|
||||
if(!id.size())
|
||||
{
|
||||
//std::cerr<<"No gist id is provided. Creating new gist...\n";
|
||||
writeLog(0, "No Gist id is provided. Creating new Gist...", LOG_LEVEL_ERROR);
|
||||
retVal = webPost("https://api.github.com/gists", buildGistData(path, content), getSystemProxy(), token, &retData);
|
||||
if(retVal != 201)
|
||||
{
|
||||
//std::cerr<<"Create new Gist failed! Return data:\n"<<retData<<"\n";
|
||||
writeLog(0, "Create new Gist failed! Return data:\n" + retData, LOG_LEVEL_ERROR);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
url = "https://gist.githubusercontent.com/" + username + "/" + id + "/raw/" + path;
|
||||
//std::cerr<<"Gist id provided. Modifying Gist...\n";
|
||||
writeLog(0, "Gist id provided. Modifying Gist...", LOG_LEVEL_INFO);
|
||||
if(writeManageURL)
|
||||
content = "#!MANAGED-CONFIG " + url + "\n" + content;
|
||||
retVal = webPatch("https://api.github.com/gists/" + id, buildGistData(path, content), getSystemProxy(), token, &retData);
|
||||
if(retVal != 200)
|
||||
{
|
||||
//std::cerr<<"Modify gist failed! Return data:\n"<<retData<<"\n";
|
||||
writeLog(0, "Modify Gist failed! Return data:\n" + retData, LOG_LEVEL_ERROR);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
json.Parse(retData.data());
|
||||
GetMember(json, "id", id);
|
||||
if(json.HasMember("owner"))
|
||||
GetMember(json["owner"], "login", username);
|
||||
url = "https://gist.githubusercontent.com/" + username + "/" + id + "/raw/" + path;
|
||||
//std::cerr<<"Writing to Gist success!\nGenerator: "<<name<<"\nPath: "<<path<<"\nRaw URL: "<<url<<"\nGist owner: "<<username<<"\n";
|
||||
writeLog(0, "Writing to Gist success!\nGenerator: " + name + "\nPath: " + path + "\nRaw URL: " + url + "\nGist owner: " + username, LOG_LEVEL_INFO);
|
||||
|
||||
ini.EraseSection();
|
||||
ini.Set("token", token);
|
||||
ini.Set("id", id);
|
||||
ini.Set("username", username);
|
||||
|
||||
ini.SetCurrentSection(path);
|
||||
ini.EraseSection();
|
||||
ini.Set("type", name);
|
||||
ini.Set("url", url);
|
||||
|
||||
ini.ToFile("gistconf.ini");
|
||||
return 0;
|
||||
}
|
||||
9
src/upload.h
Normal file
9
src/upload.h
Normal file
@ -0,0 +1,9 @@
|
||||
#ifndef UPLOAD_H_INCLUDED
|
||||
#define UPLOAD_H_INCLUDED
|
||||
|
||||
#include <string>
|
||||
|
||||
std::string buildGistData(std::string name, std::string content);
|
||||
int uploadGist(std::string name, std::string path, std::string content, bool writeManageURL);
|
||||
|
||||
#endif // UPLOAD_H_INCLUDED
|
||||
Loading…
Reference in New Issue
Block a user