| @@ -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) { | ||||