| 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 |