/* Copyright (C) 2024 m-privacy GmbH
 *
 * This is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this software; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
 * USA.
 */


#include <cstddef>
#include <cstdlib>
#include <cstdint>
#include <errno.h>
#include <libgen.h>
#include <mp_utils.h>
#include <sys/stat.h>
#ifdef WIN32
#include <direct.h>
#include <shlobj.h>
#else
#include <dirent.h>
#include <pwd.h>
#include <unistd.h>
#endif /* WIN32 */

#include "rfb/LogWriter.h"
#include "UrlWhitelistHandler.h"
#include "NativeMessagingApp.h"

static rfb::LogWriter vlog("NativeMessagingApp");

namespace NativeMessagingApp {

	// For 'TightGate-Pro Extension'. When run as an extension, it starts with specific params which the viewer wouldn't understand, and would complain about. Hence this manual check:
	bool startedAsNativeMessagingApp(int argc, char* argv[]) {
		for (int i = 1; i < argc; i++) {
			if (starts_with(argv[i], "magicurlify@m-privacy.de") ||
					starts_with(argv[i], "tightgate-pro-extension@m-privacy.de") ||
					starts_with(argv[i], "chrome-extension://") || // basically allowing all add-ons that speak to us, to speak with to us (which we are already - nearly - doing by blindly allowing all temporary ID's to communicate).
					starts_with(argv[i], "chrome-extension://obbeeofaibdijkmemjdholepjlkfjdno/") ||
					starts_with(argv[i], "chrome-extension://gjhfbjmfhdnbibehldgeppckpdoblhpm/")) {
				return true;
			}
		}
		return false;
	}

	int readLoop(void) {
		uint32_t messageLength;
		// read messages and send response
		while (fread(&messageLength, sizeof messageLength, 1, stdin) == 1) {
			// read message into buffer
			char* buf = (char*) malloc(messageLength + 1);
			if (!buf) {
				vlog.error("%s: memory allocation failed. Stopping reading loop: %m", __func__);
				return 1;
			}
			if (fread(buf, sizeof *buf, messageLength, stdin) != messageLength) {
				vlog.error("%s: failed to read content of incoming message with fread: %m. Stopping reading loop", __func__);
				return 1;
			}
			buf[messageLength] = '\0';
			vlog.debug("%s: received message: %s", __func__, buf);

			char* action;
			char* url;
			if (parseJson(buf, &action, &url) != 0) {
				vlog.error("%s: something went wrong while parsing json. Did the browser add-on send us something unexpected? Aborting...", __func__);
				return 1;
			}

			vlog.debug("%s: parsed json received from browser add-on: ", __func__);
			vlog.debug("%s: -> action '%s'", __func__, action);
			vlog.debug("%s: -> url '%s'", __func__, url);

			if (action && !strcmp(action, "get_whitelists")) {
				sendWhitelists();
				free(buf);
				free(action);
				free(url);
				return 0; // Only sending whitelists and quitting!
			}

			if (action && !strcmp(action, "check")) {
				vlog.error("%s: action is 'check' is not implemented in the viewer! Only the browserchoice has it (used for Firefox add-on with Manifest v2)", __func__);
			}

			free(buf);
			free(action);
			free(url);
		}



		if (ferror(stdin)) {
			vlog.error("%s: failed to read message length for incoming message: %m", __func__);
		}

		return !feof(stdin); // return success on EOF. This means the add-on is done with us. This could be a problem too if we expect more data
	}

	void sendWhitelists() {
		char* whitelistsContent = UrlWhitelistHandler::readAllWhitelistsAsString(NULL); // TODO this can't be null. It'll have to be the config dir!

		size_t responseSize = strlen(whitelistsContent) + strlen("{\"whitelist_content\": \"%s\"}") - 2 + 1;
		char* response = (char*) malloc(responseSize);
		snprintf(response, responseSize, "{\"whitelist_content\": \"%s\"}", whitelistsContent);
		response[responseSize - 1] = '\0';

		char* responseEscaped = escapeJsonString(response);
		vlog.debug("%s: trying to send: <%s>", __func__, responseEscaped);
		sendResponse(responseEscaped);
	}

	char* unescapeJsonString(const char* input) {
		size_t len = strlen(input);
		char* output = (char*) malloc(len + 1); // Allocate memory for the unescaped string
		if (!output) {
			return NULL; // Handle memory allocation failure
		}

		const char* src = input;  // Pointer to iterate over input string
		char* dest = output;      // Pointer to iterate over output string

		while (*src) {
			if (*src == '\\' && (*(src + 1) == '"' || *(src + 1) == '\\')) {
				// If backslash is followed by " or \, skip the backslash
				src++;
			}
			*dest++ = *src++; // Copy the current character to output
		}
		*dest = '\0'; // Null-terminate the unescaped string

		return output;
	}

	char* escapeJsonString(const char* input) {
		size_t len = strlen(input);
		size_t escapedLen = 0;

		// Allocate enough space (worst case: every character could be a new line, which are escaped twice, so triple the size)
		char* escaped = (char*) malloc(3 * len + 1);
		if (!escaped) {
			vlog.error("%s: Failed to allocate memory", __func__);
			return NULL;
		}

		for (size_t i = 0; i < len; i++) {
			switch (input[i]) {
			case '\"':
				escaped[escapedLen++] = '\\';
				escaped[escapedLen++] = '\"';
				break;
			case '\\':
				escaped[escapedLen++] = '\\';
				escaped[escapedLen++] = '\\';
				break;
			case '\n':
				escaped[escapedLen++] = '\\';
				escaped[escapedLen++] = '\\';
				escaped[escapedLen++] = 'n';
				break;
			case '\t':
				escaped[escapedLen++] = '\\';
				escaped[escapedLen++] = 't';
				break;
			default:
				escaped[escapedLen++] = input[i];
				break;
			}
		}

		escaped[escapedLen] = '\0';
		return escaped;
	}

	int parseJson(const char* input, char** actionP, char** urlP) {
		if (strstr(input, "\\\"")) {
			vlog.debug("Detected escaped quotes, unescaping before parsing. Can Firefox send a message without previously stringifying?");
			char* unescapedInput = unescapeJsonString(input);
			if (!unescapedInput) {
				return 0;
			}
			int result = doParseJson(unescapedInput, actionP, urlP);
			free(unescapedInput);
			return result;
		} else {
			vlog.debug("Detected normal quotes, using new JSON parser.");
			return doParseJson(input, actionP, urlP);
		}
	}

	int doParseJson(const char* input, char** actionP, char** urlP) {
		// TODO Once Browserchoice is integrated in the vncviewer, it would be nice to use the json library we use there instead (C++)
		const char* actionStart = strstr(input, "\"action\":\"");
		if (!actionStart) {
			vlog.error("%s: failed to parse json: 'action' not found", __func__);
			return 1;
		}
		actionStart += 10;

		const char* actionEnd = strstr(actionStart, "\"");
		if (!actionEnd) {
			vlog.error("%s: failed to parse json: invalid input format", __func__);
			return 1;
		}

		size_t actionLength = actionEnd - actionStart;

		*actionP = (char*) malloc(actionLength + 1);
		char* action = *actionP;
		if (!action) {
			vlog.error("%s: failed to allocate memory for 'action'", __func__);
			return 1;
		}
		strncpy(action, actionStart, actionLength);
		action[actionLength] = '\0';

		const char* urlStart = strstr(input, "\"url\":\"");
		if (!urlStart) {
			vlog.error("%s: failed to parse json: 'url' not found", __func__);
			return 1;
		}
		urlStart += 7;

		const char* urlEnd = strstr(urlStart, "\"");
		if (!urlEnd) {
			vlog.error("%s: failed to parse json: invalid input format", __func__);
			return 0;
		}

		size_t urlLength = urlEnd - urlStart;

		*urlP = (char*) malloc(urlLength + 1);
		char* url = *urlP;
		if (!url) {
			vlog.error("%s: failed to allocate memory for 'url'", __func__);
			return 1;
		}
		strncpy(url, urlStart, urlLength);
		url[urlLength] = '\0';

		return 0;
	}

	void sendResponse(const char* responseText) {
		size_t responseLength = strlen(responseText) + strlen(u8"\"%s\"") - 2; // Subtract 2 to exclude %s

		char* response = (char*) malloc(responseLength + 1); // +1 for null terminator
		if (!response) {
			vlog.error("%s: Error: memory allocation failed. Aborting and closing Browserchoice altogether...", __func__);
			exit(EXIT_FAILURE);
		}

		snprintf(response, responseLength + 1, u8"\"%s\"", responseText);

		if (fwrite(&responseLength, sizeof(uint32_t), 1, stdout) != 1 ||
			fwrite(response, responseLength, 1, stdout) != 1) {
			perror("fwrite");
			exit(EXIT_FAILURE);
		}

		fflush(stdout);

		free(response);
	}

	void scanExtensionDir(const char* basePath, char* allowedOrigins) {
#ifdef WIN32
		char searchPath[MAX_PATH];
		snprintf(searchPath, MAX_PATH, "%s\\*", basePath);

		WIN32_FIND_DATA findFileData;
		HANDLE hFind = FindFirstFile(searchPath, &findFileData);

		if (hFind == INVALID_HANDLE_VALUE) {
			vlog.debug("%s: Unable to list directories in '%s'", __func__, basePath);
			return;
		}

		do {
			if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
				const char* dirName = findFileData.cFileName;

				if (strcmp(dirName, ".") == 0 || strcmp(dirName, "..") == 0) {
					continue;
				}

				vlog.debug("%s: Found extension ID directory: %s in %s", __func__, dirName, basePath);

				char origin[256];
				snprintf(origin, sizeof(origin), ",\n    \"chrome-extension://%s/\"", dirName); // I can always add a comma, as there will always be 'predefined ID's' before'
				strcat(allowedOrigins, origin);
			}
		} while (FindNextFile(hFind, &findFileData) != 0);

		FindClose(hFind);
#else
		DIR* dir = opendir(basePath);
		if (!dir) {
			vlog.debug("%s: Unable to list directories in '%s'", __func__, basePath);
			return;
		}

		struct dirent* entry;
		while ((entry = readdir(dir)) != NULL) {
			if (entry->d_type == DT_DIR) {
				const char* dirName = entry->d_name;

				if (strcmp(dirName, ".") == 0 || strcmp(dirName, "..") == 0) {
					continue;
				}

				vlog.debug("%s: Found extension ID directory: %s in %s", __func__, dirName, basePath);

				char origin[512];
				snprintf(origin, 512, ",\n    \"chrome-extension://%s/\"", dirName);
				strcat(allowedOrigins, origin);
				origin[511] = '\0';
			}
		}

		closedir(dir);
#endif /* WIN32 */
	}

	char* buildFirefoxAllowedExtensions() {
		const char* allowedExtensions = "\"allowed_extensions\": [\n"
			"    \"tightgate-pro-extension@m-privacy.de\"\n"
			"  ]\n";

		char* firefoxAllowedExtensions = strdup(allowedExtensions);
		if (!firefoxAllowedExtensions) {
			vlog.error("%s: Memory allocation failed", __func__);
			return NULL;
		}
		return firefoxAllowedExtensions;
	}

	char* buildChromeAllowedOrigins() {
		const char* predefinedExtensions[] = {
			"chrome-extension://gjhfbjmfhdnbibehldgeppckpdoblhpm/",
			"chrome-extension://obbeeofaibdijkmemjdholepjlkfjdno/"
		};
		const int numPredefinedExtensions = sizeof(predefinedExtensions) / sizeof(predefinedExtensions[0]);

		char* allowedOrigins = (char*) malloc(16384);
		if (!allowedOrigins) {
			vlog.error("%s: Memory allocation failed", __func__);
			return NULL;
		}
		strcpy(allowedOrigins, "\"allowed_origins\": [\n");

		for (int i = 0; i < numPredefinedExtensions; i++) {
			if (i > 0) {
				strcat(allowedOrigins, ",\n");
			}
			strcat(allowedOrigins, "    \"");
			strcat(allowedOrigins, predefinedExtensions[i]);
			strcat(allowedOrigins, "\"");
		}

		vlog.debug("%s: Added predefined extension IDs to allowed_origins JSON array", __func__);

#ifdef WIN32
		char baseDir[MAX_PATH];
		if (SHGetFolderPath(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, baseDir) != S_OK) {
			vlog.error("%s: Unable to retrieve %%appdata%% path", __func__);
			free(allowedOrigins);
			return NULL;
		}

		char chromePath[MAX_PATH];
		snprintf(chromePath, MAX_PATH, "%s\\Google\\Chrome\\User Data\\Default\\Local Extension Settings", baseDir);
		chromePath[MAX_PATH - 1] = '\0';

		char edgePath[MAX_PATH];
		snprintf(edgePath, MAX_PATH, "%s\\Microsoft\\Edge\\User Data\\Default\\Local Extension Settings", baseDir);
		edgePath[MAX_PATH - 1] = '\0';

		scanExtensionDir(chromePath, allowedOrigins);
		scanExtensionDir(edgePath, allowedOrigins);

		strcat(allowedOrigins, "\n  ]\n");

		vlog.debug("%s: Finished building JSON array for allowed_origins: %s", __func__, allowedOrigins);
#else
		struct passwd *pw = getpwuid(getuid());
		if (!pw) {
			vlog.error("buildAllowedOrigins: Unable to retrieve home directory");
			return NULL;
		}

		const char* homeDir = pw->pw_dir;

		char chromePath[PATH_MAX];
		snprintf(chromePath, sizeof(chromePath), "%s/.config/google-chrome/Default/Local Extension Settings", homeDir);
		chromePath[PATH_MAX - 1] = '\0';

		char edgePath[PATH_MAX];
		snprintf(edgePath, sizeof(edgePath), "%s/.config/microsoft-edge/Default/Local Extension Settings", homeDir);
		edgePath[PATH_MAX - 1] = '\0';

		scanExtensionDir(chromePath, allowedOrigins);
		scanExtensionDir(edgePath, allowedOrigins);

		strcat(allowedOrigins, "\n  ]\n");
		vlog.debug("buildAllowedOrigins: Finished building JSON array for allowed_origins: %s", allowedOrigins);
#endif /* WIN32 */
		return allowedOrigins;
	}

#ifndef WIN32
	void mkdir_recursive(const char *path) {
		char *subpath, *fullpath;

		fullpath = strdup(path); // Create a copy of the path to avoid modifying the original one
		if (!fullpath) {
			vlog.error("%s: strdup failed for path: %s", __func__, path);
			return;
		}

		subpath = dirname(fullpath);

		if (strlen(subpath) > 1) {
			mkdir_recursive(subpath);
		}

		if (!mkdir(path, 0755)) {
			if (errno != EEXIST) {  // Directory already exists is not an error
				vlog.error("%s: mkdir failed for path: %s, errno: %d", __func__, path, errno);
			}
		}

		free(fullpath);
	}
#endif /* not WIN32 */

	void addManifestJsonToRegistry(const char* jsonPath) {
#ifdef WIN32
		char* keyName = NULL;
		if (strstr(jsonPath, "chrome.json")) {
			keyName = "SOFTWARE\\Google\\Chrome\\NativeMessagingHosts\\de.m_privacy.tightgate";
		} else if (strstr(jsonPath, "firefox.json")) {
			keyName = "SOFTWARE\\Mozilla\\NativeMessagingHosts\\de.m_privacy.tightgate";
		} else {
			vlog.error("%s: Can't add key for manifest files that aren't named chrome.json or firefox.json");
			return;
		}

		HKEY key;
		LONG result = RegCreateKeyEx(
									 HKEY_CURRENT_USER,
									 keyName,
									 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &key, NULL);

		if (result == ERROR_SUCCESS) {
			result = RegSetValueEx(key, NULL, 0, REG_SZ, (LPBYTE)jsonPath, strlen(jsonPath) + 1);
			if (result != ERROR_SUCCESS) {
				vlog.error("%s: Unable to set registry value for jsonPath: %s", __func__, jsonPath);
			}
			RegCloseKey(key);
		} else {
			vlog.error("%s: Unable to create registry key", __func__);
		}
#else
		vlog.debug("%s: no registry in Linux :) It's enough to have the manifest files in the right place", __func__);
#endif /* WIN32 */
	}

	char* getVncviewerBinaryPath() {
#ifdef WIN32
		char exePath[MAX_PATH] = {0};
		if (!GetModuleFileName(NULL, exePath, MAX_PATH)) {
			vlog.error("%s: GetModuleFileName failed", __func__);
			return NULL;
		}

		char* escapedExePath = escapeJsonString(exePath);
		if (!escapedExePath) {
			vlog.error("%s: Memory allocation failed for escapedExePath", __func__);
			return NULL;
		}
		return escapedExePath;
#else
		char* binPath = (char*) malloc(PATH_MAX);
		if (!binPath) {
			vlog.error("%s: Failed to allocate memory for vncviewer binary (ourselves)", __func__);
			return NULL;
		}
		ssize_t binPathLength = readlink("/proc/self/exe", binPath, PATH_MAX - 1);
		if (binPathLength == -1) {
			vlog.error("%s: Failed to get path to vncviewer binary (ourselves)", __func__);
			return NULL;
		}
		binPath[binPathLength] = '\0';
		return binPath;
#endif /* WIN32*/
	}

	typedef enum {
		BROWSER_FIREFOX = 0,
		BROWSER_CHROME,
		BROWSER_EDGE,
		BROWSER_COUNT // Marks the number of browsers
	} Browser;

	const char* browserToString(Browser browser) {
		switch (browser) {
		case BROWSER_FIREFOX:
			return "Firefox";
		case BROWSER_CHROME:
			return "Chrome";
		case BROWSER_EDGE:
			return "Edge";
		default:
			return "Unknown";
		}
	}

	char* getManifestPath(const char* configDir, Browser browser) {
#ifdef WIN32
		const char* filename;
		switch (browser) {
		case BROWSER_FIREFOX:
			filename = "firefox.json";
			break;
		case BROWSER_CHROME:
			filename = "chrome.json";
			break;
		case BROWSER_EDGE:
			// Don't do nothing for now. Chrome's seems to be enough
			break;
		case BROWSER_COUNT:
			vlog.error("%s: invalid Browser (%d). Can't generate filename for json file...", __func__, browser);
			break;
		default:
			vlog.error("%s: invalid Browser (%d). Can't generate filename for json file...", __func__, browser);
			break;
		}
#else
		const char* filename = "de.m_privacy.tightgate.json";
#endif
#ifdef WIN32
		char manifestDir[MAX_PATH] = {0};

		if (configDir && *configDir) {
			size_t manifestDirLength = strlen(configDir) + 1; // +1 for NULL-termination
			snprintf(manifestDir, manifestDirLength, "%s", configDir);
		} else {
			char appDataPath[MAX_PATH] = {0};
			if (SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, 0, appDataPath) != S_OK) {
				vlog.error("%s: SHGetFolderPath failed", __func__);
				return NULL;
			}
			size_t manifestDirLength = strlen(appDataPath) + 4 + 1; // +4 for "\vnc", +1 for NULL-termination
			snprintf(manifestDir, manifestDirLength, "%s\\vnc", appDataPath);
		}

		if (!CreateDirectory(manifestDir, NULL) && GetLastError() != ERROR_ALREADY_EXISTS) {
			vlog.error("%s: Unable to create directory: %s", __func__, manifestDir);
			return NULL;
		}
#else /* not WIN32 */
		const char* homeDir = getenv("HOME");
		if (!homeDir) {
			vlog.error("%s: Failed to get $HOME from env)", __func__);
			return NULL;
		}
		vlog.debug("%s: browser %d (%s)", __func__, browser, browserToString(browser));

		char manifestDir[PATH_MAX];
		switch (browser) {
			// TODO: it would probably be nice to check whether the browsers are installed...
		case BROWSER_FIREFOX:
			snprintf(manifestDir, PATH_MAX, "%s/.mozilla/native-messaging-hosts", homeDir);
			break;
		case BROWSER_CHROME:
			snprintf(manifestDir, PATH_MAX, "%s/.config/google-chrome/NativeMessagingHosts", homeDir);
			break;
		case BROWSER_EDGE:
			snprintf(manifestDir, PATH_MAX, "%s/.config/microsoft-edge/NativeMessagingHosts", homeDir);
			break;
		case BROWSER_COUNT:
			vlog.error("%s: invalid Browser (%d). Can't create NativeMessagingHosts dir...", __func__, browser);
			break;
		}

		manifestDir[PATH_MAX - 1] = '\0';
		mkdir_recursive(manifestDir);
#endif /* WIN32 */

		size_t manifestPathLength = strlen(manifestDir) + strlen(filename) + 1 + 1; // +1 for path separator, +1 for NULL-termination
		char* manifestPath = (char*) malloc(manifestPathLength);
		if (!manifestPath) {
			vlog.error("%s: Memory allocation failed for manifestPath", __func__);
			return NULL;
		}
#ifdef WIN32
		snprintf(manifestPath, manifestPathLength, "%s\\%s", manifestDir, filename);
#else
		snprintf(manifestPath, manifestPathLength, "%s/%s", manifestDir, filename);
#endif
		manifestPath[manifestPathLength - 1] = '\0';
		return manifestPath;
	}

	char* buildAllowedJsonArray(Browser browser) {
		char* allowedJsonArray = NULL;
		switch (browser) {
		case BROWSER_FIREFOX:
			allowedJsonArray = buildFirefoxAllowedExtensions();
			break;
		case BROWSER_CHROME:
			allowedJsonArray = buildChromeAllowedOrigins();
			break;
		case BROWSER_EDGE:
			allowedJsonArray = buildChromeAllowedOrigins();
			break;
		case BROWSER_COUNT:
			break;
		default:
			vlog.debug("%s: not running for browser %d (%s). It only makes sense for Firefox and Chrome (Edge uses exactly the same as chrome)", __func__, browser, browserToString(browser));
			break;
		}
		return allowedJsonArray;
	}

	bool writeManifestJson(const char* vncviewerBinaryPath, const char* allowedJsonArray, const char* manifestPath) {
		char jsonContent[32768];
		snprintf(jsonContent, sizeof(jsonContent),
				 "{\n"
				 "  \"name\": \"de.m_privacy.tightgate\",\n"
				 "  \"description\": \"Receiver app for TightGate-Pro Extension\",\n"
				 "  \"path\": \"%s\",\n"
				 "  \"type\": \"stdio\",\n"
				 "  %s\n"
				 "}",
				 vncviewerBinaryPath, allowedJsonArray);

		FILE* file = fopen(manifestPath, "w");
		if (!file) {
			vlog.error("%s: Unable to open file for writing: %s", __func__, manifestPath);
			return false;
		}

		vlog.debug("%s: Opened file for writing: %s", __func__, manifestPath);

		fprintf(file, "%s", jsonContent);
		fclose(file);

		return true;
	}

	bool registerAsNativeMessagingHostApp(const char* configDir) {
		char* vncviewerBinaryPath = getVncviewerBinaryPath(); // Something like C:\\Program Files\\TightGate-Pro\\vncviewer.exe for Windows and /usr/local/bin/tightgateviewer for Linux
		vlog.debug("%s: Got vncviewerBinaryPath: %s", __func__, vncviewerBinaryPath);
		for (Browser browser = BROWSER_FIREFOX; browser < BROWSER_COUNT; browser = static_cast<Browser>(static_cast<int>(browser) + 1)) {
			char* allowedJsonArray = buildAllowedJsonArray(browser);
			if (allowedJsonArray && *allowedJsonArray) {
				vlog.debug("%s: Created 'allowed' JSON array for browser %d: %s", __func__, browser, allowedJsonArray);
			} else {
				vlog.error("%s: Failed to create an 'allowed' JSON array for browser (%d)", __func__, browser);
			}
			char* manifestPath = getManifestPath(configDir, browser);
			if (manifestPath) {
				vlog.debug("%s: Manifest path for browser %d: %s", __func__, browser, manifestPath);
			} else {
				vlog.error("%s: Failed to create a manifest path for browser (%d)", __func__, browser);
			}

			writeManifestJson((const char*) vncviewerBinaryPath, (const char*) allowedJsonArray, (const char*) manifestPath);
			addManifestJsonToRegistry(manifestPath); // Not necessary for Linux (won't do anything...)
		}

		return true;
	}
}
