OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 package org.chromium.chrome.browser.cookies; | 5 package org.chromium.chrome.browser.cookies; |
6 | 6 |
7 import android.content.Context; | 7 import android.content.Context; |
8 import android.os.AsyncTask; | 8 import android.os.AsyncTask; |
9 | 9 |
10 import org.chromium.base.ImportantFileWriterAndroid; | 10 import org.chromium.base.ImportantFileWriterAndroid; |
11 import org.chromium.base.Log; | 11 import org.chromium.base.Log; |
12 import org.chromium.base.ThreadUtils; | 12 import org.chromium.base.ThreadUtils; |
13 import org.chromium.base.annotations.CalledByNative; | 13 import org.chromium.base.annotations.CalledByNative; |
14 import org.chromium.chrome.browser.profiles.Profile; | 14 import org.chromium.chrome.browser.profiles.Profile; |
15 import org.chromium.content.browser.crypto.CipherFactory; | 15 import org.chromium.content.browser.crypto.CipherFactory; |
16 import org.chromium.content.common.CleanupReference; | 16 import org.chromium.content.common.CleanupReference; |
17 | 17 |
18 import java.io.ByteArrayOutputStream; | 18 import java.io.ByteArrayOutputStream; |
19 import java.io.DataInputStream; | 19 import java.io.DataInputStream; |
20 import java.io.DataOutputStream; | 20 import java.io.DataOutputStream; |
21 import java.io.EOFException; | |
22 import java.io.File; | 21 import java.io.File; |
23 import java.io.FileInputStream; | 22 import java.io.FileInputStream; |
24 import java.io.IOException; | 23 import java.io.IOException; |
25 import java.util.ArrayList; | 24 import java.util.ArrayList; |
26 import java.util.List; | 25 import java.util.List; |
27 | 26 |
28 import javax.crypto.Cipher; | 27 import javax.crypto.Cipher; |
29 import javax.crypto.CipherInputStream; | 28 import javax.crypto.CipherInputStream; |
30 import javax.crypto.CipherOutputStream; | 29 import javax.crypto.CipherOutputStream; |
31 | 30 |
32 /** | 31 /** |
33 * Responsible for fetching, (de)serializing, and restoring cookies between the
CookieJar and an | 32 * Responsible for fetching, (de)serializing, and restoring cookies between the
CookieJar and an |
34 * encrypted file storage. | 33 * encrypted file storage. |
35 */ | 34 */ |
36 public class CookiesFetcher { | 35 public class CookiesFetcher { |
37 /** The default file name for the encrypted cookies storage. */ | 36 /** The default file name for the encrypted cookies storage. */ |
38 private static final String DEFAULT_COOKIE_FILE_NAME = "COOKIES.DAT"; | 37 private static final String DEFAULT_COOKIE_FILE_NAME = "COOKIES.DAT"; |
39 | 38 |
40 /** Used for logging. */ | 39 /** Used for logging. */ |
41 private static final String TAG = "CookiesFetcher"; | 40 private static final String TAG = "CookiesFetcher"; |
42 | 41 |
43 /** | |
44 * Used to confirm that the current cipher key matches the previously used c
ipher key when | |
45 * restoring data. If this value cannot be read from the file, the file is
likely garbage. | |
46 * TODO(acleung): May be use real cryptographic integrity checks on the whol
e file, instead. | |
47 */ | |
48 private static final String MAGIC_STRING = "c0Ok135"; | |
49 | |
50 /** Native-side pointer. */ | 42 /** Native-side pointer. */ |
51 private final long mNativeCookiesFetcher; | 43 private final long mNativeCookiesFetcher; |
52 | 44 |
53 private final CleanupReference mCleanupReference; | 45 private final CleanupReference mCleanupReference; |
54 | 46 |
55 private final Context mContext; | 47 private final Context mContext; |
56 | 48 |
57 /** | 49 /** |
58 * Creates a new fetcher that can use to fetch cookies from cookie jar | 50 * Creates a new fetcher that can use to fetch cookies from cookie jar |
59 * or from a file. | 51 * or from a file. |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
112 } catch (RuntimeException e) { | 104 } catch (RuntimeException e) { |
113 e.printStackTrace(); | 105 e.printStackTrace(); |
114 } | 106 } |
115 } | 107 } |
116 | 108 |
117 private static void restoreCookiesInternal(final Context context) { | 109 private static void restoreCookiesInternal(final Context context) { |
118 new AsyncTask<Void, Void, List<CanonicalCookie>>() { | 110 new AsyncTask<Void, Void, List<CanonicalCookie>>() { |
119 @Override | 111 @Override |
120 protected List<CanonicalCookie> doInBackground(Void... voids) { | 112 protected List<CanonicalCookie> doInBackground(Void... voids) { |
121 // Read cookies from disk on a background thread to avoid strict
mode violations. | 113 // Read cookies from disk on a background thread to avoid strict
mode violations. |
122 ArrayList<CanonicalCookie> cookies = new ArrayList<CanonicalCook
ie>(); | 114 List<CanonicalCookie> cookies = new ArrayList<CanonicalCookie>()
; |
123 DataInputStream in = null; | 115 DataInputStream in = null; |
124 try { | 116 try { |
125 Cipher cipher = CipherFactory.getInstance().getCipher(Cipher
.DECRYPT_MODE); | 117 Cipher cipher = CipherFactory.getInstance().getCipher(Cipher
.DECRYPT_MODE); |
126 if (cipher == null) { | 118 if (cipher == null) { |
127 // Something is wrong. Can't encrypt, don't restore cook
ies. | 119 // Something is wrong. Can't encrypt, don't restore cook
ies. |
128 return cookies; | 120 return cookies; |
129 } | 121 } |
130 File fileIn = new File(fetchFileName(context)); | 122 File fileIn = new File(fetchFileName(context)); |
131 if (!fileIn.exists()) return cookies; // Nothing to read | 123 if (!fileIn.exists()) return cookies; // Nothing to read |
132 | 124 |
133 FileInputStream streamIn = new FileInputStream(fileIn); | 125 FileInputStream streamIn = new FileInputStream(fileIn); |
134 in = new DataInputStream(new CipherInputStream(streamIn, cip
her)); | 126 in = new DataInputStream(new CipherInputStream(streamIn, cip
her)); |
135 String check = in.readUTF(); | 127 cookies = CanonicalCookie.readListFromStream(in); |
136 if (!MAGIC_STRING.equals(check)) { | |
137 // Stale cookie file. Chrome might have crashed before i
t | |
138 // can delete the old file. | |
139 return cookies; | |
140 } | |
141 try { | |
142 while (true) { | |
143 CanonicalCookie cookie = CanonicalCookie.createFromS
tream(in); | |
144 cookies.add(cookie); | |
145 } | |
146 } catch (EOFException ignored) { | |
147 // We are done. | |
148 } | |
149 | 128 |
150 // The Cookie File should not be restored again. It'll be ov
erwritten | 129 // The Cookie File should not be restored again. It'll be ov
erwritten |
151 // on the next onPause. | 130 // on the next onPause. |
152 scheduleDeleteCookiesFile(context); | 131 scheduleDeleteCookiesFile(context); |
153 | 132 |
154 } catch (IOException e) { | 133 } catch (IOException e) { |
155 Log.w(TAG, "IOException during Cookie Restore"); | 134 Log.w(TAG, "IOException during Cookie Restore", e); |
156 } catch (Throwable t) { | 135 } catch (Throwable t) { |
157 Log.w(TAG, "Error restoring cookies.", t); | 136 Log.w(TAG, "Error restoring cookies.", t); |
158 } finally { | 137 } finally { |
159 try { | 138 try { |
160 if (in != null) in.close(); | 139 if (in != null) in.close(); |
161 } catch (IOException e) { | 140 } catch (IOException e) { |
162 Log.w(TAG, "IOException during Cooke Restore"); | 141 Log.w(TAG, "IOException during Cooke Restore"); |
163 } catch (Throwable t) { | 142 } catch (Throwable t) { |
164 Log.w(TAG, "Error restoring cookies.", t); | 143 Log.w(TAG, "Error restoring cookies.", t); |
165 } | 144 } |
166 } | 145 } |
167 return cookies; | 146 return cookies; |
168 } | 147 } |
169 | 148 |
170 @Override | 149 @Override |
171 protected void onPostExecute(List<CanonicalCookie> cookies) { | 150 protected void onPostExecute(List<CanonicalCookie> cookies) { |
172 // We can only access cookies and profiles on the UI thread. | 151 // We can only access cookies and profiles on the UI thread. |
173 for (CanonicalCookie cookie : cookies) { | 152 for (CanonicalCookie cookie : cookies) { |
174 nativeRestoreCookies(cookie.getUrl(), cookie.getName(), cook
ie.getValue(), | 153 nativeRestoreCookies(cookie.getUrl(), cookie.getName(), cook
ie.getValue(), |
175 cookie.getDomain(), cookie.getPath(), cookie.getCrea
tionDate(), | 154 cookie.getDomain(), cookie.getPath(), cookie.getCrea
tionDate(), |
176 cookie.getExpirationDate(), cookie.getLastAccessDate
(), | 155 cookie.getExpirationDate(), cookie.getLastAccessDate
(), |
177 cookie.isSecure(), cookie.isHttpOnly(), cookie.isSam
eSite(), | 156 cookie.isSecure(), cookie.isHttpOnly(), cookie.getSa
meSite(), |
178 cookie.getPriority()); | 157 cookie.getPriority()); |
179 } | 158 } |
180 } | 159 } |
181 }.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR); | 160 }.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR); |
182 } | 161 } |
183 | 162 |
184 /** | 163 /** |
185 * Ensure the incognito cookies are deleted when the incognito profile is go
ne. | 164 * Ensure the incognito cookies are deleted when the incognito profile is go
ne. |
186 * | 165 * |
187 * @param context Context for accessing the file system. | 166 * @param context Context for accessing the file system. |
(...skipping 24 matching lines...) Expand all Loading... |
212 } | 191 } |
213 } | 192 } |
214 return null; | 193 return null; |
215 } | 194 } |
216 }.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR); | 195 }.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR); |
217 } | 196 } |
218 | 197 |
219 @CalledByNative | 198 @CalledByNative |
220 private CanonicalCookie createCookie(String url, String name, String value,
String domain, | 199 private CanonicalCookie createCookie(String url, String name, String value,
String domain, |
221 String path, long creation, long expiration, long lastAccess, boolea
n secure, | 200 String path, long creation, long expiration, long lastAccess, boolea
n secure, |
222 boolean httpOnly, boolean sameSite, int priority) { | 201 boolean httpOnly, int sameSite, int priority) { |
223 return new CanonicalCookie(url, name, value, domain, path, creation, exp
iration, lastAccess, | 202 return new CanonicalCookie(url, name, value, domain, path, creation, exp
iration, lastAccess, |
224 secure, httpOnly, sameSite, priority); | 203 secure, httpOnly, sameSite, priority); |
225 } | 204 } |
226 | 205 |
227 @CalledByNative | 206 @CalledByNative |
228 private void onCookieFetchFinished(final CanonicalCookie[] cookies) { | 207 private void onCookieFetchFinished(final CanonicalCookie[] cookies) { |
229 // Cookies fetching requires operations with the profile and must be | 208 // Cookies fetching requires operations with the profile and must be |
230 // done in the main thread. Once that is done, do the save to disk | 209 // done in the main thread. Once that is done, do the save to disk |
231 // part in {@link AsyncTask} to avoid strict mode violations. | 210 // part in {@link AsyncTask} to avoid strict mode violations. |
232 new AsyncTask<Void, Void, Void>() { | 211 new AsyncTask<Void, Void, Void>() { |
(...skipping 11 matching lines...) Expand all Loading... |
244 Cipher cipher = CipherFactory.getInstance().getCipher(Cipher.ENCRYPT
_MODE); | 223 Cipher cipher = CipherFactory.getInstance().getCipher(Cipher.ENCRYPT
_MODE); |
245 if (cipher == null) { | 224 if (cipher == null) { |
246 // Something is wrong. Can't encrypt, don't save cookies. | 225 // Something is wrong. Can't encrypt, don't save cookies. |
247 return; | 226 return; |
248 } | 227 } |
249 | 228 |
250 ByteArrayOutputStream byteOut = new ByteArrayOutputStream(); | 229 ByteArrayOutputStream byteOut = new ByteArrayOutputStream(); |
251 CipherOutputStream cipherOut = | 230 CipherOutputStream cipherOut = |
252 new CipherOutputStream(byteOut, cipher); | 231 new CipherOutputStream(byteOut, cipher); |
253 out = new DataOutputStream(cipherOut); | 232 out = new DataOutputStream(cipherOut); |
254 | 233 CanonicalCookie.saveListToStream(out, cookies); |
255 out.writeUTF(MAGIC_STRING); | |
256 for (CanonicalCookie cookie : cookies) { | |
257 cookie.saveToStream(out); | |
258 } | |
259 out.close(); | 234 out.close(); |
260 ImportantFileWriterAndroid.writeFileAtomically( | 235 ImportantFileWriterAndroid.writeFileAtomically( |
261 fetchFileName(mContext), byteOut.toByteArray()); | 236 fetchFileName(mContext), byteOut.toByteArray()); |
262 out = null; | 237 out = null; |
263 } catch (IOException e) { | 238 } catch (IOException e) { |
264 Log.w(TAG, "IOException during Cookie Fetch"); | 239 Log.w(TAG, "IOException during Cookie Fetch"); |
265 } catch (Throwable t) { | 240 } catch (Throwable t) { |
266 Log.w(TAG, "Error storing cookies.", t); | 241 Log.w(TAG, "Error storing cookies.", t); |
267 } finally { | 242 } finally { |
268 try { | 243 try { |
(...skipping 20 matching lines...) Expand all Loading... |
289 @CalledByNative | 264 @CalledByNative |
290 private CanonicalCookie[] createCookiesArray(int size) { | 265 private CanonicalCookie[] createCookiesArray(int size) { |
291 return new CanonicalCookie[size]; | 266 return new CanonicalCookie[size]; |
292 } | 267 } |
293 | 268 |
294 private native long nativeInit(); | 269 private native long nativeInit(); |
295 private static native void nativeDestroy(long nativeCookiesFetcher); | 270 private static native void nativeDestroy(long nativeCookiesFetcher); |
296 private native void nativePersistCookies(long nativeCookiesFetcher); | 271 private native void nativePersistCookies(long nativeCookiesFetcher); |
297 private static native void nativeRestoreCookies(String url, String name, Str
ing value, | 272 private static native void nativeRestoreCookies(String url, String name, Str
ing value, |
298 String domain, String path, long creation, long expiration, long las
tAccess, | 273 String domain, String path, long creation, long expiration, long las
tAccess, |
299 boolean secure, boolean httpOnly, boolean sameSite, int priority); | 274 boolean secure, boolean httpOnly, int sameSite, int priority); |
300 } | 275 } |
OLD | NEW |