-
Notifications
You must be signed in to change notification settings - Fork 682
/
CookieDataCodec.java
94 lines (87 loc) · 3.3 KB
/
CookieDataCodec.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
package play.mvc;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Provides operations around the encoding and decoding of Cookie data.
*/
public class CookieDataCodec {
/**
* Cookie session parser for cookie created by version 1.2.5 or before.
* <p>
* We need it to support old Play 1.2.5 session data encoding so that the cookie data doesn't become invalid when
* applications are upgraded to a newer version of Play
* </p>
*/
public static final Pattern oldCookieSessionParser = Pattern.compile("\u0000([^:]*):([^\u0000]*)\u0000");
/**
* @param map
* the map to decode data into.
* @param data
* the data to decode.
* @throws UnsupportedEncodingException
* if the encoding is not supported
*/
public static void decode(Map<String, String> map, String data) throws UnsupportedEncodingException {
// support old Play 1.2.5 session data encoding so that the cookie data doesn't become invalid when
// applications are upgraded to a newer version of Play
if (data.startsWith("%00") && data.contains("%3A") && data.endsWith("%00")) {
String sessionData = URLDecoder.decode(data, StandardCharsets.UTF_8);
Matcher matcher = oldCookieSessionParser.matcher(sessionData);
while (matcher.find()) {
map.put(matcher.group(1), matcher.group(2));
}
return;
}
String[] keyValues = data.split("&");
for (String keyValue : keyValues) {
String[] split = keyValue.split("=", 2);
if (split.length == 2) {
map.put(URLDecoder.decode(split[0], StandardCharsets.UTF_8), URLDecoder.decode(split[1], StandardCharsets.UTF_8));
}
}
}
/**
* @param map
* the data to encode.
* @return the encoded data.
* @throws UnsupportedEncodingException
* if the encoding is not supported
*/
public static String encode(Map<String, String> map) throws UnsupportedEncodingException {
StringBuilder data = new StringBuilder();
String separator = "";
for (Map.Entry<String, String> entry : map.entrySet()) {
if (entry.getValue() != null) {
data.append(separator).append(URLEncoder.encode(entry.getKey(), StandardCharsets.UTF_8)).append("=")
.append(URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8));
separator = "&";
}
}
return data.toString();
}
/**
* Constant time for same length String comparison, to prevent timing attacks
*
* @param a
* The string a
* @param b
* the string b
* @return true is the 2 strings are equals
*/
public static boolean safeEquals(String a, String b) {
if (a.length() != b.length()) {
return false;
} else {
char equal = 0;
for (int i = 0; i < a.length(); i++) {
equal |= a.charAt(i) ^ b.charAt(i);
}
return equal == 0;
}
}
}