Skip to content

Commit

Permalink
fix(cookies): sanitize url before retrieving/setting cookies
Browse files Browse the repository at this point in the history
Co-authored-by: Mike Summerfeldt <20338451+IT-MikeS@users.noreply.github.com>
Co-authored-by: Mark Anderson <mark@ionic.io>
  • Loading branch information
3 people authored Jul 12, 2023
1 parent 56a2d34 commit ca40634
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 92 deletions.
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package com.getcapacitor.plugin;

import android.util.Log;
import com.getcapacitor.Bridge;
import java.net.CookieManager;
import java.net.CookiePolicy;
import java.net.CookieStore;
import java.net.HttpCookie;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
Expand All @@ -22,6 +24,8 @@ public class CapacitorCookieManager extends CookieManager {

private final String serverUrl;

private final String TAG = "CapacitorCookies";

/**
* Create a new cookie manager with the default cookie store and policy
*/
Expand All @@ -43,21 +47,28 @@ public CapacitorCookieManager(CookieStore store, CookiePolicy policy, Bridge bri
this.serverUrl = bridge.getServerUrl();
}

public String getSanitizedDomain(String url) {
public String getSanitizedDomain(String url) throws URISyntaxException {
if (url == null || url.isEmpty()) {
url = this.localUrl;
url = this.serverUrl;
}

try {
new URI(url);
} catch (Exception ex) {
return this.serverUrl;
} catch (Exception ignored) {
url = this.localUrl;

try {
new URI(url);
} catch (Exception error) {
Log.e(TAG, "Failed to get sanitized URL.", error);
throw error;
}
}

return url;
}

private String getDomainFromCookieString(String cookie) {
private String getDomainFromCookieString(String cookie) throws URISyntaxException {
String[] domain = cookie.toLowerCase(Locale.ROOT).split("domain=");
return getSanitizedDomain(domain.length <= 1 ? null : domain[1].split(";")[0].trim());
}
Expand All @@ -68,7 +79,15 @@ private String getDomainFromCookieString(String cookie) {
* @return value the cookies as a string, using the format of the 'Cookie' HTTP request header
*/
public String getCookieString(String url) {
return webkitCookieManager.getCookie(url);
try {
url = getSanitizedDomain(url);
Log.i(TAG, "Getting cookies at: '" + url + "'");
return webkitCookieManager.getCookie(url);
} catch (Exception error) {
Log.e(TAG, "Failed to get cookies at the given URL.", error);
}

return null;
}

/**
Expand Down Expand Up @@ -120,8 +139,14 @@ public HttpCookie[] getCookies(String url) {
* @param value the cookie as a string, using the format of the 'Set-Cookie' HTTP response header
*/
public void setCookie(String url, String value) {
webkitCookieManager.setCookie(url, value);
flush();
try {
url = getSanitizedDomain(url);
Log.i(TAG, "Setting cookie '" + value + "' at: '" + url + "'");
webkitCookieManager.setCookie(url, value);
flush();
} catch (Exception error) {
Log.e(TAG, "Failed to set cookie.", error);
}
}

/**
Expand Down Expand Up @@ -169,11 +194,13 @@ public void put(URI uri, Map<String, List<String>> responseHeaders) {

// process each of the headers
for (String headerValue : Objects.requireNonNull(responseHeaders.get(headerKey))) {
// Set at server url
setCookie(uri.toString(), headerValue);
try {
// Set at the requested server url
setCookie(uri.toString(), headerValue);

// Set at local url or domain
setCookie(getDomainFromCookieString(headerValue), headerValue);
// Set at the defined domain in the response or at default capacitor hosted url
setCookie(getDomainFromCookieString(headerValue), headerValue);
} catch (Exception ignored) {}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,115 +31,64 @@ public boolean isEnabled() {
return pluginConfig.getBoolean("enabled", false);
}

/**
* Helper function for getting the serverUrl from the Capacitor Config. Returns an empty
* string if it is invalid and will auto-reject through {@code call}
* @param call the {@code PluginCall} context
* @return the string of the server specified in the Capacitor config
*/
private String getServerUrl(@Nullable PluginCall call) {
String url = (call == null) ? this.bridge.getServerUrl() : call.getString("url", this.bridge.getServerUrl());

if (url == null || url.isEmpty()) {
url = this.bridge.getLocalUrl();
}

URI uri = getUri(url);
if (uri == null) {
if (call != null) {
call.reject("Invalid URL. Check that \"server\" is passed in correctly");
}

return "";
}

return url;
}

/**
* Try to parse a url string and if it can't be parsed, return null
* @param url the url string to try to parse
* @return a parsed URI
*/
private URI getUri(String url) {
try {
return new URI(url);
} catch (Exception ex) {
return null;
}
}

@JavascriptInterface
public String getCookies() {
try {
String url = getServerUrl(null);
if (!url.isEmpty()) {
String cookieString = cookieManager.getCookieString(url);
return (null == cookieString) ? "" : cookieString;
}
} catch (Exception e) {
e.printStackTrace();
}

return "";
String cookieString = cookieManager.getCookieString(null);
return (null == cookieString) ? "" : cookieString;
}

@JavascriptInterface
public void setCookie(String domain, String action) {
String url = cookieManager.getSanitizedDomain(domain);

if (!url.isEmpty()) {
cookieManager.setCookie(url, action);
}
cookieManager.setCookie(domain, action);
}

@PluginMethod
public void getCookies(PluginCall call) {
String url = getServerUrl(call);
if (!url.isEmpty()) {
JSObject cookiesMap = new JSObject();
HttpCookie[] cookies = cookieManager.getCookies(url);
for (HttpCookie cookie : cookies) {
cookiesMap.put(cookie.getName(), cookie.getValue());
}
call.resolve(cookiesMap);
String url = call.getString("url");
JSObject cookiesMap = new JSObject();
HttpCookie[] cookies = cookieManager.getCookies(url);
for (HttpCookie cookie : cookies) {
cookiesMap.put(cookie.getName(), cookie.getValue());
}
call.resolve(cookiesMap);
}

@PluginMethod
public void setCookie(PluginCall call) {
String key = call.getString("key");
if (null == key) {
call.reject("Must provide key");
}
String value = call.getString("value");
String url = getServerUrl(call);
if (null == value) {
call.reject("Must provide value");
}
String url = call.getString("url");
String expires = call.getString("expires", "");
String path = call.getString("path", "/");

if (!url.isEmpty()) {
cookieManager.setCookie(url, key, value, expires, path);
call.resolve();
}
cookieManager.setCookie(url, key, value, expires, path);
call.resolve();
}

@PluginMethod
public void deleteCookie(PluginCall call) {
String key = call.getString("key");
String url = getServerUrl(call);
if (!url.isEmpty()) {
cookieManager.setCookie(url, key + "=; Expires=Wed, 31 Dec 2000 23:59:59 GMT");
call.resolve();
if (null == key) {
call.reject("Must provide key");
}
String url = call.getString("url");
cookieManager.setCookie(url, key + "=; Expires=Wed, 31 Dec 2000 23:59:59 GMT");
call.resolve();
}

@PluginMethod
public void clearCookies(PluginCall call) {
String url = getServerUrl(call);
if (!url.isEmpty()) {
HttpCookie[] cookies = cookieManager.getCookies(url);
for (HttpCookie cookie : cookies) {
cookieManager.setCookie(url, cookie.getName() + "=; Expires=Wed, 31 Dec 2000 23:59:59 GMT");
}
call.resolve();
String url = call.getString("url");
HttpCookie[] cookies = cookieManager.getCookies(url);
for (HttpCookie cookie : cookies) {
cookieManager.setCookie(url, cookie.getName() + "=; Expires=Wed, 31 Dec 2000 23:59:59 GMT");
}
call.resolve();
}

@PluginMethod
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public class CapacitorCookieManager {
}

public func getServerUrl() -> URL? {
return self.config?.serverURL
return self.config?.serverURL ?? self.config?.localURL
}

private func isUrlSanitized(_ urlString: String) -> Bool {
Expand Down

0 comments on commit ca40634

Please sign in to comment.