@@ -90,12 +90,17 @@ struct ModuleInfo { | |||||
int added = 0; | int added = 0; | ||||
double lastAdded = NAN; | double lastAdded = NAN; | ||||
}; | }; | ||||
// pluginSlug -> (moduleSlug -> ModuleInfo) | |||||
/** pluginSlug -> (moduleSlug -> ModuleInfo) */ | |||||
extern std::map<std::string, std::map<std::string, ModuleInfo>> moduleInfos; | extern std::map<std::string, std::map<std::string, ModuleInfo>> moduleInfos; | ||||
/** Returns a ModuleInfo if exists for the given slugs. | /** Returns a ModuleInfo if exists for the given slugs. | ||||
*/ | */ | ||||
ModuleInfo* getModuleInfo(const std::string& pluginSlug, const std::string& moduleSlug); | ModuleInfo* getModuleInfo(const std::string& pluginSlug, const std::string& moduleSlug); | ||||
/** pluginSlug -> {moduleSlug} */ | |||||
extern std::map<std::string, std::set<std::string>> moduleWhitelist; | |||||
bool isModuleWhitelisted(const std::string& pluginSlug, const std::string& moduleSlug); | |||||
void init(); | void init(); | ||||
json_t* toJson(); | json_t* toJson(); | ||||
void fromJson(json_t* rootJ); | void fromJson(json_t* rootJ); | ||||
@@ -609,10 +609,15 @@ struct Browser : widget::OpaqueWidget { | |||||
if (model->hidden) | if (model->hidden) | ||||
return false; | return false; | ||||
// Filter moduleInfo setting if enabled is false | |||||
settings::ModuleInfo* mi = settings::getModuleInfo(model->plugin->slug, model->slug); | settings::ModuleInfo* mi = settings::getModuleInfo(model->plugin->slug, model->slug); | ||||
if (mi && !mi->enabled) | if (mi && !mi->enabled) | ||||
return false; | return false; | ||||
// Filter if not whitelisted by library | |||||
if (!settings::isModuleWhitelisted(model->plugin->slug, model->slug)) | |||||
return false; | |||||
// Filter favorites | // Filter favorites | ||||
if (favorite) { | if (favorite) { | ||||
if (!mi || !mi->favorite) | if (!mi || !mi->favorite) | ||||
@@ -163,12 +163,25 @@ void checkUpdates() { | |||||
} | } | ||||
DEFER({json_decref(userResJ);}); | DEFER({json_decref(userResJ);}); | ||||
// Get library manifests | |||||
std::string manifestsUrl = API_URL + "/library/manifests"; | |||||
json_t* manifestsReq = json_object(); | |||||
json_object_set(manifestsReq, "version", json_string(APP_VERSION_MAJOR.c_str())); | |||||
json_t* manifestsResJ = network::requestJson(network::METHOD_GET, manifestsUrl, manifestsReq); | |||||
json_decref(manifestsReq); | |||||
if (!manifestsResJ) { | |||||
WARN("Request for library manifests failed"); | |||||
updateStatus = "Could not query plugin manifests"; | |||||
return; | |||||
} | |||||
DEFER({json_decref(manifestsResJ);}); | |||||
// Get user's plugins list | // Get user's plugins list | ||||
std::string pluginsUrl = API_URL + "/plugins"; | std::string pluginsUrl = API_URL + "/plugins"; | ||||
json_t* pluginsResJ = network::requestJson(network::METHOD_GET, pluginsUrl, NULL, getTokenCookies()); | json_t* pluginsResJ = network::requestJson(network::METHOD_GET, pluginsUrl, NULL, getTokenCookies()); | ||||
if (!pluginsResJ) { | if (!pluginsResJ) { | ||||
WARN("Request for user's plugins failed"); | WARN("Request for user's plugins failed"); | ||||
updateStatus = "Could not query plugins"; | |||||
updateStatus = "Could not query user's plugins"; | |||||
return; | return; | ||||
} | } | ||||
DEFER({json_decref(pluginsResJ);}); | DEFER({json_decref(pluginsResJ);}); | ||||
@@ -180,19 +193,6 @@ void checkUpdates() { | |||||
return; | return; | ||||
} | } | ||||
// Get library manifests | |||||
std::string manifestsUrl = API_URL + "/library/manifests"; | |||||
json_t* manifestsReq = json_object(); | |||||
json_object_set(manifestsReq, "version", json_string(APP_VERSION_MAJOR.c_str())); | |||||
json_t* manifestsResJ = network::requestJson(network::METHOD_GET, manifestsUrl, manifestsReq); | |||||
json_decref(manifestsReq); | |||||
if (!manifestsResJ) { | |||||
WARN("Request for library manifests failed"); | |||||
updateStatus = "Could not query updates"; | |||||
return; | |||||
} | |||||
DEFER({json_decref(manifestsResJ);}); | |||||
json_t* manifestsJ = json_object_get(manifestsResJ, "manifests"); | json_t* manifestsJ = json_object_get(manifestsResJ, "manifests"); | ||||
json_t* pluginsJ = json_object_get(pluginsResJ, "plugins"); | json_t* pluginsJ = json_object_get(pluginsResJ, "plugins"); | ||||
@@ -252,36 +252,42 @@ void checkUpdates() { | |||||
} | } | ||||
// Get module whitelist | // Get module whitelist | ||||
// TODO | |||||
// { | |||||
// std::string whitelistUrl = API_URL + "/modules"; | |||||
// json_t* whitelistResJ = network::requestJson(network::METHOD_GET, whitelistUrl, NULL, getTokenCookies()); | |||||
// if (!whitelistResJ) { | |||||
// WARN("Request for module whitelist failed"); | |||||
// updateStatus = "Could not query updates"; | |||||
// return; | |||||
// } | |||||
// DEFER({json_decref(whitelistResJ);}); | |||||
// std::map<std::string, std::set<std::string>> moduleWhitelist; | |||||
// json_t* pluginsJ = json_object_get(whitelistResJ, "plugins"); | |||||
// // Iterate plugins | |||||
// const char* pluginSlug; | |||||
// json_t* modulesJ; | |||||
// json_object_foreach(pluginsJ, pluginSlug, modulesJ) { | |||||
// // Iterate modules in plugin | |||||
// size_t moduleIndex; | |||||
// json_t* moduleSlugJ; | |||||
// json_array_foreach(modulesJ, moduleIndex, moduleSlugJ) { | |||||
// std::string moduleSlug = json_string_value(moduleSlugJ); | |||||
// // Insert module in whitelist | |||||
// moduleWhitelist[pluginSlug].insert(moduleSlug); | |||||
// } | |||||
// } | |||||
// settings::moduleWhitelist = moduleWhitelist; | |||||
// } | |||||
{ | |||||
std::string whitelistUrl = API_URL + "/modules"; | |||||
json_t* whitelistResJ = network::requestJson(network::METHOD_GET, whitelistUrl, NULL, getTokenCookies()); | |||||
if (!whitelistResJ) { | |||||
WARN("Request for module whitelist failed"); | |||||
updateStatus = "Could not query user's modules"; | |||||
return; | |||||
} | |||||
DEFER({json_decref(whitelistResJ);}); | |||||
// Clone plugin slugs from settings to temporary whitelist. | |||||
// This makes plugins entirely hidden if removed. | |||||
std::map<std::string, std::set<std::string>> moduleWhitelist; | |||||
for (const auto& pluginPair : settings::moduleWhitelist) { | |||||
// Create an empty set | |||||
moduleWhitelist[pluginPair.first]; | |||||
} | |||||
// Iterate plugins | |||||
json_t* pluginsJ = json_object_get(whitelistResJ, "plugins"); | |||||
const char* pluginSlug; | |||||
json_t* modulesJ; | |||||
json_object_foreach(pluginsJ, pluginSlug, modulesJ) { | |||||
// Iterate modules in plugin | |||||
size_t moduleIndex; | |||||
json_t* moduleSlugJ; | |||||
json_array_foreach(modulesJ, moduleIndex, moduleSlugJ) { | |||||
std::string moduleSlug = json_string_value(moduleSlugJ); | |||||
// Insert module in whitelist | |||||
DEBUG("plugin %s module %s", pluginSlug, moduleSlug.c_str()); | |||||
moduleWhitelist[pluginSlug].insert(moduleSlug); | |||||
} | |||||
} | |||||
settings::moduleWhitelist = moduleWhitelist; | |||||
} | |||||
updateStatus = ""; | updateStatus = ""; | ||||
refreshRequested = true; | refreshRequested = true; | ||||
@@ -138,8 +138,6 @@ json_t* requestJson(Method method, const std::string& url, json_t* dataJ, const | |||||
curl_easy_cleanup(curl); | curl_easy_cleanup(curl); | ||||
curl_slist_free_all(headers); | curl_slist_free_all(headers); | ||||
DEBUG("response: %s", resText.c_str()); | |||||
if (res != CURLE_OK) { | if (res != CURLE_OK) { | ||||
WARN("Could not request %s: %s", urlS.c_str(), curl_easy_strerror(res)); | WARN("Could not request %s: %s", urlS.c_str(), curl_easy_strerror(res)); | ||||
return NULL; | return NULL; | ||||
@@ -63,6 +63,7 @@ bool discordUpdateActivity = true; | |||||
BrowserSort browserSort = BROWSER_SORT_UPDATED; | BrowserSort browserSort = BROWSER_SORT_UPDATED; | ||||
float browserZoom = -1.f; | float browserZoom = -1.f; | ||||
std::map<std::string, std::map<std::string, ModuleInfo>> moduleInfos; | std::map<std::string, std::map<std::string, ModuleInfo>> moduleInfos; | ||||
std::map<std::string, std::set<std::string>> moduleWhitelist; | |||||
ModuleInfo* getModuleInfo(const std::string& pluginSlug, const std::string& moduleSlug) { | ModuleInfo* getModuleInfo(const std::string& pluginSlug, const std::string& moduleSlug) { | ||||
@@ -76,6 +77,18 @@ ModuleInfo* getModuleInfo(const std::string& pluginSlug, const std::string& modu | |||||
} | } | ||||
bool isModuleWhitelisted(const std::string& pluginSlug, const std::string& moduleSlug) { | |||||
auto pluginIt = moduleWhitelist.find(pluginSlug); | |||||
// All modules in a plugin are visible if plugin set is empty. | |||||
if (pluginIt == moduleWhitelist.end()) | |||||
return true; | |||||
auto moduleIt = pluginIt->second.find(moduleSlug); | |||||
if (moduleIt == pluginIt->second.end()) | |||||
return false; | |||||
return true; | |||||
} | |||||
void init() { | void init() { | ||||
settingsPath = asset::user("settings.json"); | settingsPath = asset::user("settings.json"); | ||||
} | } | ||||
@@ -159,6 +172,7 @@ json_t* toJson() { | |||||
json_object_set_new(rootJ, "browserZoom", json_real(browserZoom)); | json_object_set_new(rootJ, "browserZoom", json_real(browserZoom)); | ||||
// moduleInfos | |||||
json_t* moduleInfosJ = json_object(); | json_t* moduleInfosJ = json_object(); | ||||
for (const auto& pluginPair : moduleInfos) { | for (const auto& pluginPair : moduleInfos) { | ||||
json_t* pluginJ = json_object(); | json_t* pluginJ = json_object(); | ||||
@@ -188,6 +202,17 @@ json_t* toJson() { | |||||
} | } | ||||
json_object_set_new(rootJ, "moduleInfos", moduleInfosJ); | json_object_set_new(rootJ, "moduleInfos", moduleInfosJ); | ||||
// moduleWhitelist | |||||
json_t* moduleWhitelistJ = json_object(); | |||||
for (const auto& pluginPair : moduleWhitelist) { | |||||
json_t* pluginJ = json_array(); | |||||
for (const std::string& moduleSlug : pluginPair.second) { | |||||
json_array_append_new(pluginJ, json_stringn(moduleSlug.c_str(), moduleSlug.size())); | |||||
} | |||||
json_object_set_new(moduleWhitelistJ, pluginPair.first.c_str(), pluginJ); | |||||
} | |||||
json_object_set_new(rootJ, "moduleWhitelist", moduleWhitelistJ); | |||||
return rootJ; | return rootJ; | ||||
} | } | ||||
@@ -367,6 +392,21 @@ void fromJson(json_t* rootJ) { | |||||
} | } | ||||
} | } | ||||
} | } | ||||
moduleWhitelist.clear(); | |||||
json_t* moduleWhitelistJ = json_object_get(rootJ, "moduleWhitelist"); | |||||
if (moduleWhitelistJ) { | |||||
const char* pluginSlug; | |||||
json_t* pluginJ; | |||||
json_object_foreach(moduleWhitelistJ, pluginSlug, pluginJ) { | |||||
size_t moduleIndex; | |||||
json_t* moduleJ; | |||||
json_array_foreach(pluginJ, moduleIndex, moduleJ) { | |||||
std::string moduleSlug = json_string_value(moduleJ); | |||||
moduleWhitelist[pluginSlug].insert(moduleSlug); | |||||
} | |||||
} | |||||
} | |||||
} | } | ||||
void save(std::string path) { | void save(std::string path) { | ||||