#include #include #include #include #include #include "cookie_manager.h" #include "types/callbacks_complete.h" #include "utils/flutter.h" #include "utils/log.h" namespace flutter_inappwebview_plugin { using namespace Microsoft::WRL; CookieManager::CookieManager(const FlutterInappwebviewWindowsPlugin* plugin) : plugin(plugin), ChannelDelegate(plugin->registrar->messenger(), CookieManager::METHOD_CHANNEL_NAME_PREFIX) {} void CookieManager::HandleMethodCall(const flutter::MethodCall& method_call, std::unique_ptr> result) { auto& arguments = std::get(*method_call.arguments()); auto& methodName = method_call.method_name(); auto webViewEnvironmentId = get_optional_fl_map_value(arguments, "webViewEnvironmentId"); auto webViewEnvironment = webViewEnvironmentId.has_value() && map_contains(plugin->webViewEnvironmentManager->webViewEnvironments, webViewEnvironmentId.value()) ? plugin->webViewEnvironmentManager->webViewEnvironments.at(webViewEnvironmentId.value()).get() : nullptr; auto result_ = std::shared_ptr>(std::move(result)); auto callback = [this, result_, methodName, arguments](WebViewEnvironment* webViewEnvironment) { if (!webViewEnvironment) { result_->Error("0", "Cannot obtain the WebViewEnvironment!"); return; } if (string_equals(methodName, "setCookie")) { setCookie(webViewEnvironment, arguments, [result_](const bool& created) { result_->Success(created); }); } else if (string_equals(methodName, "getCookie")) { auto url = get_fl_map_value(arguments, "url"); auto name = get_fl_map_value(arguments, "name"); getCookie(webViewEnvironment, url, name, [result_](const flutter::EncodableValue& cookie) { result_->Success(cookie); }); } else if (string_equals(methodName, "getCookies")) { auto url = get_fl_map_value(arguments, "url"); getCookies(webViewEnvironment, url, [result_](const flutter::EncodableList& cookies) { result_->Success(cookies); }); } else if (string_equals(methodName, "deleteCookie")) { auto url = get_fl_map_value(arguments, "url"); auto name = get_fl_map_value(arguments, "name"); auto path = get_fl_map_value(arguments, "path"); auto domain = get_optional_fl_map_value(arguments, "domain"); deleteCookie(webViewEnvironment, url, name, path, domain, [result_](const bool& deleted) { result_->Success(deleted); }); } else if (string_equals(methodName, "deleteCookies")) { auto url = get_fl_map_value(arguments, "url"); auto path = get_fl_map_value(arguments, "path"); auto domain = get_optional_fl_map_value(arguments, "domain"); deleteCookies(webViewEnvironment, url, path, domain, [result_](const bool& deleted) { result_->Success(deleted); }); } else if (string_equals(methodName, "deleteAllCookies")) { deleteAllCookies(webViewEnvironment, [result_](const bool& deleted) { result_->Success(deleted); }); } else { result_->NotImplemented(); } }; if (webViewEnvironment) { callback(webViewEnvironment); } else { plugin->webViewEnvironmentManager->createOrGetDefaultWebViewEnvironment([callback](WebViewEnvironment* webViewEnvironment) { callback(webViewEnvironment); }); } } void CookieManager::setCookie(WebViewEnvironment* webViewEnvironment, const flutter::EncodableMap& map, std::function completionHandler) const { if (!plugin || !plugin->webViewEnvironmentManager) { if (completionHandler) { completionHandler(false); } return; } auto url = get_fl_map_value(map, "url"); auto name = get_fl_map_value(map, "name"); auto value = get_fl_map_value(map, "value"); auto path = get_fl_map_value(map, "path"); auto domain = get_optional_fl_map_value(map, "domain"); auto expiresDate = get_optional_fl_map_value(map, "expiresDate"); auto maxAge = get_optional_fl_map_value(map, "maxAge"); auto isSecure = get_optional_fl_map_value(map, "isSecure"); auto isHttpOnly = get_optional_fl_map_value(map, "isHttpOnly"); auto sameSite = get_optional_fl_map_value(map, "sameSite"); nlohmann::json parameters = { {"url", url}, {"name", name}, {"value", value}, {"path", path} }; if (domain.has_value()) { parameters["domain"] = domain.value(); } if (expiresDate.has_value()) { parameters["expires"] = expiresDate.value() / 1000; } if (maxAge.has_value()) { // time(NULL) represents the current unix timestamp in seconds parameters["expires"] = time(NULL) + maxAge.value(); } if (isSecure.has_value()) { parameters["secure"] = isSecure.value(); } if (isHttpOnly.has_value()) { parameters["httpOnly"] = isHttpOnly.value(); } if (sameSite.has_value()) { parameters["sameSite"] = sameSite.value(); } auto hr = webViewEnvironment->getWebView()->CallDevToolsProtocolMethod(L"Network.setCookie", utf8_to_wide(parameters.dump()).c_str(), Callback( [completionHandler](HRESULT errorCode, LPCWSTR returnObjectAsJson) { if (completionHandler) { completionHandler(succeededOrLog(errorCode)); } return S_OK; } ).Get()); if (failedAndLog(hr) && completionHandler) { completionHandler(false); } } void CookieManager::getCookie(WebViewEnvironment* webViewEnvironment, const std::string& url, const std::string& name, std::function completionHandler) const { if (!plugin || !plugin->webViewEnvironmentManager) { if (completionHandler) { completionHandler(make_fl_value()); } return; } nlohmann::json parameters = { {"urls", std::vector{url}} }; auto hr = webViewEnvironment->getWebView()->CallDevToolsProtocolMethod(L"Network.getCookies", utf8_to_wide(parameters.dump()).c_str(), Callback( [completionHandler, name](HRESULT errorCode, LPCWSTR returnObjectAsJson) { if (succeededOrLog(errorCode)) { nlohmann::json json = nlohmann::json::parse(wide_to_utf8(returnObjectAsJson)); auto jsonCookies = json["cookies"].get>(); for (auto& jsonCookie : jsonCookies) { auto cookieName = jsonCookie["name"].get(); if (string_equals(name, cookieName)) { completionHandler(flutter::EncodableMap{ {"name", cookieName}, {"value", jsonCookie["value"].get()}, {"domain", jsonCookie["domain"].get()}, {"path", jsonCookie["path"].get()}, {"expiresDate", jsonCookie["expires"].get()}, {"isHttpOnly", jsonCookie["httpOnly"].get()}, {"isSecure", jsonCookie["secure"].get()}, {"isSessionOnly", jsonCookie["session"].get()}, {"sameSite", jsonCookie.contains("sameSite") ? jsonCookie["sameSite"].get() : make_fl_value()} }); return S_OK; } } } if (completionHandler) { completionHandler(make_fl_value()); } return S_OK; } ).Get()); if (failedAndLog(hr) && completionHandler) { completionHandler(make_fl_value()); } } void CookieManager::getCookies(WebViewEnvironment* webViewEnvironment, const std::string& url, std::function completionHandler) const { if (!plugin || !plugin->webViewEnvironmentManager) { if (completionHandler) { completionHandler({}); } return; } nlohmann::json parameters = { {"urls", std::vector{url}} }; auto hr = webViewEnvironment->getWebView()->CallDevToolsProtocolMethod(L"Network.getCookies", utf8_to_wide(parameters.dump()).c_str(), Callback( [completionHandler](HRESULT errorCode, LPCWSTR returnObjectAsJson) { std::vector cookies = {}; if (succeededOrLog(errorCode)) { nlohmann::json json = nlohmann::json::parse(wide_to_utf8(returnObjectAsJson)); auto jsonCookies = json["cookies"].get>(); for (auto& jsonCookie : jsonCookies) { cookies.push_back(flutter::EncodableMap{ {"name", jsonCookie["name"].get()}, {"value", jsonCookie["value"].get()}, {"domain", jsonCookie["domain"].get()}, {"path", jsonCookie["path"].get()}, {"expiresDate", jsonCookie["expires"].get()}, {"isHttpOnly", jsonCookie["httpOnly"].get()}, {"isSecure", jsonCookie["secure"].get()}, {"isSessionOnly", jsonCookie["session"].get()}, {"sameSite", jsonCookie.contains("sameSite") ? jsonCookie["sameSite"].get() : make_fl_value()} }); } } if (completionHandler) { completionHandler(cookies); } return S_OK; } ).Get()); if (failedAndLog(hr) && completionHandler) { completionHandler({}); } } void CookieManager::deleteCookie(WebViewEnvironment* webViewEnvironment, const std::string& url, const std::string& name, const std::string& path, const std::optional& domain, std::function completionHandler) const { if (!plugin || !plugin->webViewEnvironmentManager) { if (completionHandler) { completionHandler(false); } return; } nlohmann::json parameters = { {"url", url}, {"name", name}, {"path", path} }; if (domain.has_value()) { parameters["domain"] = domain.value(); } auto hr = webViewEnvironment->getWebView()->CallDevToolsProtocolMethod(L"Network.deleteCookies", utf8_to_wide(parameters.dump()).c_str(), Callback( [completionHandler](HRESULT errorCode, LPCWSTR returnObjectAsJson) { if (completionHandler) { completionHandler(succeededOrLog(errorCode)); } return S_OK; } ).Get()); if (failedAndLog(hr) && completionHandler) { completionHandler(false); } } void CookieManager::deleteCookies(WebViewEnvironment* webViewEnvironment, const std::string& url, const std::string& path, const std::optional& domain, std::function completionHandler) const { if (!plugin || !plugin->webViewEnvironmentManager) { if (completionHandler) { completionHandler(false); } return; } getCookies(webViewEnvironment, url, [this, webViewEnvironment, url, path, domain, completionHandler](const flutter::EncodableList& cookies) { auto callbacksComplete = std::make_shared>( [completionHandler](const std::vector& values) { if (completionHandler) { completionHandler(true); } }); for (auto& cookie : cookies) { auto cookieMap = std::get(cookie); auto name = get_fl_map_value(cookieMap, "name"); deleteCookie(webViewEnvironment, url, name, path, domain, [callbacksComplete](const bool& deleted) { callbacksComplete->addValue(deleted); }); } }); } void CookieManager::deleteAllCookies(WebViewEnvironment* webViewEnvironment, std::function completionHandler) const { if (!plugin || !plugin->webViewEnvironmentManager) { if (completionHandler) { completionHandler(false); } return; } auto hr = webViewEnvironment->getWebView()->CallDevToolsProtocolMethod(L"Network.clearBrowserCookies", L"{}", Callback( [completionHandler](HRESULT errorCode, LPCWSTR returnObjectAsJson) { if (completionHandler) { completionHandler(succeededOrLog(errorCode)); } return S_OK; } ).Get()); if (failedAndLog(hr) && completionHandler) { completionHandler(false); } } CookieManager::~CookieManager() { debugLog("dealloc CookieManager"); plugin = nullptr; } }