Implement IP Address Pinning. https://redmine.stoutner.com/issues/212
[PrivacyBrowser.git] / app / src / main / java / com / stoutner / privacybrowser / helpers / DomainsDatabaseHelper.java
1 /*
2  * Copyright © 2017-2019 Soren Stoutner <soren@stoutner.com>.
3  *
4  * This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
5  *
6  * Privacy Browser is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * Privacy Browser is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with Privacy Browser.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 package com.stoutner.privacybrowser.helpers;
21
22 import android.content.ContentValues;
23 import android.content.Context;
24 import android.content.SharedPreferences;
25 import android.database.Cursor;
26 import android.database.sqlite.SQLiteDatabase;
27 import android.database.sqlite.SQLiteOpenHelper;
28 import android.preference.PreferenceManager;
29
30 public class DomainsDatabaseHelper extends SQLiteOpenHelper {
31     private static final int SCHEMA_VERSION = 9;
32     static final String DOMAINS_DATABASE = "domains.db";
33     static final String DOMAINS_TABLE = "domains";
34
35     public static final String _ID = "_id";
36     public static final String DOMAIN_NAME = "domainname";
37     public static final String ENABLE_JAVASCRIPT = "enablejavascript";
38     public static final String ENABLE_FIRST_PARTY_COOKIES = "enablefirstpartycookies";
39     public static final String ENABLE_THIRD_PARTY_COOKIES = "enablethirdpartycookies";
40     public static final String ENABLE_DOM_STORAGE = "enabledomstorage";
41     public static final String ENABLE_FORM_DATA = "enableformdata";  // Form data can be removed once the minimum API >= 26.
42     public static final String ENABLE_EASYLIST = "enableeasylist";
43     public static final String ENABLE_EASYPRIVACY = "enableeasyprivacy";
44     public static final String ENABLE_FANBOYS_ANNOYANCE_LIST = "enablefanboysannoyancelist";
45     public static final String ENABLE_FANBOYS_SOCIAL_BLOCKING_LIST = "enablefanboyssocialblockinglist";
46     public static final String ENABLE_ULTRAPRIVACY = "enableultraprivacy";
47     public static final String BLOCK_ALL_THIRD_PARTY_REQUESTS = "blockallthirdpartyrequests";
48     public static final String USER_AGENT = "useragent";
49     public static final String FONT_SIZE = "fontsize";
50     public static final String SWIPE_TO_REFRESH = "swipetorefresh";
51     public static final String NIGHT_MODE = "nightmode";
52     public static final String DISPLAY_IMAGES = "displayimages";
53     public static final String PINNED_SSL_CERTIFICATE = "pinnedsslcertificate";
54     public static final String SSL_ISSUED_TO_COMMON_NAME = "sslissuedtocommonname";
55     public static final String SSL_ISSUED_TO_ORGANIZATION = "sslissuedtoorganization";
56     public static final String SSL_ISSUED_TO_ORGANIZATIONAL_UNIT = "sslissuedtoorganizationalunit";
57     public static final String SSL_ISSUED_BY_COMMON_NAME = "sslissuedbycommonname";
58     public static final String SSL_ISSUED_BY_ORGANIZATION = "sslissuedbyorganization";
59     public static final String SSL_ISSUED_BY_ORGANIZATIONAL_UNIT = "sslissuedbyorganizationalunit";
60     public static final String SSL_START_DATE = "sslstartdate";
61     public static final String SSL_END_DATE = "sslenddate";
62     public static final String PINNED_IP_ADDRESSES = "pinned_ip_addresses";
63     public static final String IP_ADDRESSES = "ip_addresses";
64
65     // Swipe to refresh constants.
66     public static final int SWIPE_TO_REFRESH_SYSTEM_DEFAULT = 0;
67     public static final int SWIPE_TO_REFRESH_ENABLED = 1;
68     public static final int SWIPE_TO_REFRESH_DISABLED = 2;
69
70     // Night mode constants.
71     public static final int NIGHT_MODE_SYSTEM_DEFAULT = 0;
72     public static final int NIGHT_MODE_ENABLED = 1;
73     public static final int NIGHT_MODE_DISABLED = 2;
74
75     // Display webpage images constants.
76     public static final int DISPLAY_WEBPAGE_IMAGES_SYSTEM_DEFAULT = 0;
77     public static final int DISPLAY_WEBPAGE_IMAGES_ENABLED = 1;
78     public static final int DISPLAY_WEBPAGE_IMAGES_DISABLED = 2;
79
80     static final String CREATE_DOMAINS_TABLE = "CREATE TABLE " + DOMAINS_TABLE + " (" +
81             _ID + " INTEGER PRIMARY KEY, " +
82             DOMAIN_NAME + " TEXT, " +
83             ENABLE_JAVASCRIPT + " BOOLEAN, " +
84             ENABLE_FIRST_PARTY_COOKIES + " BOOLEAN, " +
85             ENABLE_THIRD_PARTY_COOKIES + " BOOLEAN, " +
86             ENABLE_DOM_STORAGE + " BOOLEAN, " +
87             ENABLE_FORM_DATA + " BOOLEAN, " +
88             ENABLE_EASYLIST + " BOOLEAN, " +
89             ENABLE_EASYPRIVACY + " BOOLEAN, " +
90             ENABLE_FANBOYS_ANNOYANCE_LIST + " BOOLEAN, " +
91             ENABLE_FANBOYS_SOCIAL_BLOCKING_LIST + " BOOLEAN, " +
92             ENABLE_ULTRAPRIVACY + " BOOLEAN, " +
93             BLOCK_ALL_THIRD_PARTY_REQUESTS + " BOOLEAN, " +
94             USER_AGENT + " TEXT, " +
95             FONT_SIZE + " INTEGER, " +
96             SWIPE_TO_REFRESH + " INTEGER, " +
97             NIGHT_MODE + " INTEGER, " +
98             DISPLAY_IMAGES + " INTEGER, " +
99             PINNED_SSL_CERTIFICATE + " BOOLEAN, " +
100             SSL_ISSUED_TO_COMMON_NAME + " TEXT, " +
101             SSL_ISSUED_TO_ORGANIZATION + " TEXT, " +
102             SSL_ISSUED_TO_ORGANIZATIONAL_UNIT + " TEXT, " +
103             SSL_ISSUED_BY_COMMON_NAME + " TEXT, " +
104             SSL_ISSUED_BY_ORGANIZATION + " TEXT, " +
105             SSL_ISSUED_BY_ORGANIZATIONAL_UNIT + " TEXT, " +
106             SSL_START_DATE + " INTEGER, " +
107             SSL_END_DATE + " INTEGER, " +
108             PINNED_IP_ADDRESSES + " BOOLEAN, " +
109             IP_ADDRESSES + " TEXT)";
110
111     private final Context appContext;
112
113     // Initialize the database.  The lint warnings for the unused parameters are suppressed.
114     public DomainsDatabaseHelper(Context context, @SuppressWarnings("UnusedParameters") String name, SQLiteDatabase.CursorFactory cursorFactory, @SuppressWarnings("UnusedParameters") int version) {
115         super(context, DOMAINS_DATABASE, cursorFactory, SCHEMA_VERSION);
116
117         // Store a handle for the context.
118         appContext = context;
119     }
120
121     @Override
122     public void onCreate(SQLiteDatabase domainsDatabase) {
123         // Create the domains table.
124         domainsDatabase.execSQL(CREATE_DOMAINS_TABLE);
125     }
126
127     @Override
128     public void onUpgrade(SQLiteDatabase domainsDatabase, int oldVersion, int newVersion) {
129         // Upgrade the database table.
130         switch (oldVersion) {
131             // Upgrade from schema version 1.
132             case 1:
133                 // Add the display images column.
134                 domainsDatabase.execSQL("ALTER TABLE " + DOMAINS_TABLE + " ADD COLUMN " + DISPLAY_IMAGES + " INTEGER");
135
136             // Upgrade from schema version 2.
137             case 2:
138                 //  Add the SSL certificate columns.
139                 domainsDatabase.execSQL("ALTER TABLE " + DOMAINS_TABLE + " ADD COLUMN " + PINNED_SSL_CERTIFICATE + " BOOLEAN");
140                 domainsDatabase.execSQL("ALTER TABLE " + DOMAINS_TABLE + " ADD COLUMN " + SSL_ISSUED_TO_COMMON_NAME + " TEXT");
141                 domainsDatabase.execSQL("ALTER TABLE " + DOMAINS_TABLE + " ADD COLUMN " + SSL_ISSUED_TO_ORGANIZATION + " TEXT");
142                 domainsDatabase.execSQL("ALTER TABLE " + DOMAINS_TABLE + " ADD COLUMN " + SSL_ISSUED_TO_ORGANIZATIONAL_UNIT + " TEXT");
143                 domainsDatabase.execSQL("ALTER TABLE " + DOMAINS_TABLE + " ADD COLUMN " + SSL_ISSUED_BY_COMMON_NAME + " TEXT");
144                 domainsDatabase.execSQL("ALTER TABLE " + DOMAINS_TABLE + " ADD COLUMN " + SSL_ISSUED_BY_ORGANIZATION + " TEXT");
145                 domainsDatabase.execSQL("ALTER TABLE " + DOMAINS_TABLE + " ADD COLUMN " + SSL_ISSUED_BY_ORGANIZATIONAL_UNIT + " TEXT");
146                 domainsDatabase.execSQL("ALTER TABLE " + DOMAINS_TABLE + " ADD COLUMN " + SSL_START_DATE + " INTEGER");
147                 domainsDatabase.execSQL("ALTER TABLE " + DOMAINS_TABLE + " ADD COLUMN " + SSL_END_DATE + " INTEGER");
148
149             // Upgrade from schema version 3.
150             case 3:
151                 // Add the Night Mode column.
152                 domainsDatabase.execSQL("ALTER TABLE " + DOMAINS_TABLE + " ADD COLUMN " + NIGHT_MODE + " INTEGER");
153
154             // Upgrade from schema version 4.
155             case 4:
156                 // Add the block lists columns.
157                 domainsDatabase.execSQL("ALTER TABLE " + DOMAINS_TABLE + " ADD COLUMN " + ENABLE_EASYLIST + " BOOLEAN");
158                 domainsDatabase.execSQL("ALTER TABLE " + DOMAINS_TABLE + " ADD COLUMN " + ENABLE_EASYPRIVACY + " BOOLEAN");
159                 domainsDatabase.execSQL("ALTER TABLE " + DOMAINS_TABLE + " ADD COLUMN " + ENABLE_FANBOYS_ANNOYANCE_LIST + " BOOLEAN");
160                 domainsDatabase.execSQL("ALTER TABLE " + DOMAINS_TABLE + " ADD COLUMN " + ENABLE_FANBOYS_SOCIAL_BLOCKING_LIST + " BOOLEAN");
161
162                 // Get a handle for the shared preference.
163                 SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(appContext);
164
165                 // Get the default block list settings.
166                 boolean easyListEnabled = sharedPreferences.getBoolean("easylist", true);
167                 boolean easyPrivacyEnabled = sharedPreferences.getBoolean("easyprivacy", true);
168                 boolean fanboyAnnoyanceListEnabled = sharedPreferences.getBoolean("fanboys_annoyance_list", true);
169                 boolean fanboySocialBlockingListEnabled = sharedPreferences.getBoolean("fanboys_social_blocking_list", true);
170
171                 // Set EasyList for existing rows according to the current system-wide default.
172                 if (easyListEnabled) {
173                     domainsDatabase.execSQL("UPDATE " + DOMAINS_TABLE + " SET " + ENABLE_EASYLIST + " = " + 1);
174                 } else {
175                     domainsDatabase.execSQL("UPDATE " + DOMAINS_TABLE + " SET " + ENABLE_EASYLIST + " = " + 0);
176                 }
177
178                 // Set EasyPrivacy for existing rows according to the current system-wide default.
179                 if (easyPrivacyEnabled) {
180                     domainsDatabase.execSQL("UPDATE " + DOMAINS_TABLE + " SET " + ENABLE_EASYPRIVACY + " = " + 1);
181                 } else {
182                     domainsDatabase.execSQL("UPDATE " + DOMAINS_TABLE + " SET " + ENABLE_EASYPRIVACY + " = " + 0);
183                 }
184
185                 // Set Fanboy's Annoyance List for existing rows according to the current system-wide default.
186                 if (fanboyAnnoyanceListEnabled) {
187                     domainsDatabase.execSQL("UPDATE " + DOMAINS_TABLE + " SET " + ENABLE_FANBOYS_ANNOYANCE_LIST + " = " + 1);
188                 } else {
189                     domainsDatabase.execSQL("UPDATE " + DOMAINS_TABLE + " SET " + ENABLE_FANBOYS_ANNOYANCE_LIST + " = " + 0);
190                 }
191
192                 // Set Fanboy's Social Blocking List for existing rows according to the current system-wide default.
193                 if (fanboySocialBlockingListEnabled) {
194                     domainsDatabase.execSQL("UPDATE " + DOMAINS_TABLE + " SET " + ENABLE_FANBOYS_SOCIAL_BLOCKING_LIST + " = " + 1);
195                 } else {
196                     domainsDatabase.execSQL("UPDATE " + DOMAINS_TABLE + " SET " + ENABLE_FANBOYS_SOCIAL_BLOCKING_LIST + " = " + 0);
197                 }
198
199             // Upgrade from schema version 5.
200             case 5:
201                 // Add the swipe to refresh column.
202                 domainsDatabase.execSQL("ALTER TABLE " + DOMAINS_TABLE + " ADD COLUMN " + SWIPE_TO_REFRESH + " INTEGER");
203
204             // Upgrade from schema version 6.
205             case 6:
206                 // Add the block all third-party requests column.
207                 domainsDatabase.execSQL("ALTER TABLE " + DOMAINS_TABLE + " ADD COLUMN " + BLOCK_ALL_THIRD_PARTY_REQUESTS + " BOOLEAN");
208
209             // Upgrade from schema version 7.
210             case 7:
211                 // Add the UltraPrivacy column.
212                 domainsDatabase.execSQL("ALTER TABLE " + DOMAINS_TABLE + " ADD COLUMN " + ENABLE_ULTRAPRIVACY + " BOOLEAN");
213
214                 // Enable it for all existing rows.
215                 domainsDatabase.execSQL("UPDATE " + DOMAINS_TABLE + " SET " + ENABLE_ULTRAPRIVACY + " = " + 1);
216
217             // Upgrade from schema version 8.
218             case 8:
219                 // Add the Pinned IP Addresses columns.
220                 domainsDatabase.execSQL("ALTER TABLE " + DOMAINS_TABLE + " ADD COLUMN " + PINNED_IP_ADDRESSES + " BOOLEAN");
221                 domainsDatabase.execSQL("ALTER TABLE " + DOMAINS_TABLE + " ADD COLUMN " + IP_ADDRESSES + " TEXT");
222         }
223     }
224
225     Cursor getCompleteCursorOrderedByDomain() {
226         // Get a readable database handle.
227         SQLiteDatabase domainsDatabase = this.getReadableDatabase();
228
229         // Return everything in the domains table ordered by the domain name.  The second argument is `null` because there are no `selectionArgs`.
230         return domainsDatabase.rawQuery("SELECT * FROM " + DOMAINS_TABLE + " ORDER BY " + DOMAIN_NAME + " ASC", null);
231     }
232
233     public Cursor getDomainNameCursorOrderedByDomain() {
234         // Get a readable database handle.
235         SQLiteDatabase domainsDatabase = this.getReadableDatabase();
236
237         // Get everything in the domains table ordered by the domain name.
238         String GET_CURSOR_ORDERED_BY_DOMAIN = "SELECT " + _ID + ", " + DOMAIN_NAME +
239                 " FROM " + DOMAINS_TABLE +
240                 " ORDER BY " + DOMAIN_NAME + " ASC";
241
242         // Return the results as a `Cursor`.  The second argument is `null` because there are no `selectionArgs`.  The cursor can't be closed because it is needed in the calling activity.
243         return domainsDatabase.rawQuery(GET_CURSOR_ORDERED_BY_DOMAIN, null);
244     }
245
246     public Cursor getDomainNameCursorOrderedByDomainExcept(int databaseId) {
247         // Get a readable database handle.
248         SQLiteDatabase domainsDatabase = this.getReadableDatabase();
249
250         // Prepare the SQL statement to select all rows except that with `databaseId`.
251         String GET_CURSOR_ORDERED_BY_DOMAIN_EXCEPT = "SELECT " + _ID + ", " + DOMAIN_NAME +
252                 " FROM " + DOMAINS_TABLE +
253                 " WHERE " + _ID + " IS NOT " + databaseId +
254                 " ORDER BY " + DOMAIN_NAME + " ASC";
255
256         // Return the results as a `Cursor`.  The second argument is `null` because there are no `selectionArgs`.  The cursor can't be closed because it is needed in the calling activity.
257         return domainsDatabase.rawQuery(GET_CURSOR_ORDERED_BY_DOMAIN_EXCEPT, null);
258     }
259
260     public Cursor getCursorForId(int databaseId) {
261         // Get a readable database handle.
262         SQLiteDatabase domainsDatabase = this.getReadableDatabase();
263
264         // Prepare the SQL statement to get the `Cursor` for `databaseId`.
265         String GET_CURSOR_FOR_ID = "SELECT * FROM " + DOMAINS_TABLE +
266                 " WHERE " + _ID + " = " + databaseId;
267
268         // Return the results as a `Cursor`.  The second argument is `null` because there are no `selectionArgs`.  The cursor can't be closed because it is needed in the calling activity.
269         return domainsDatabase.rawQuery(GET_CURSOR_FOR_ID, null);
270     }
271
272     public Cursor getCursorForDomainName(String domainName) {
273         // Get a readable database handle.
274         SQLiteDatabase domainsDatabase = this.getReadableDatabase();
275
276         // Return a cursor for the requested domain name.
277         return domainsDatabase.query(DOMAINS_TABLE, null, DOMAIN_NAME + " = " + "\"" + domainName + "\"", null, null, null, null);
278
279     }
280
281     public int addDomain(String domainName) {
282         // Store the domain data in a `ContentValues`.
283         ContentValues domainContentValues = new ContentValues();
284
285         // Get a handle for the shared preference.
286         SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(appContext);
287
288         // Get the default settings.
289         boolean javaScriptEnabled = sharedPreferences.getBoolean("javascript", false);
290         boolean firstPartyCookiesEnabled = sharedPreferences.getBoolean("first_party_cookies", false);
291         boolean thirdPartyCookiesEnabled = sharedPreferences.getBoolean("third_party_cookies", false);
292         boolean domStorageEnabled = sharedPreferences.getBoolean("dom_storage", false);
293         boolean saveFormDataEnabled = sharedPreferences.getBoolean("save_form_data", false);  // Form data can be removed once the minimum API >= 26.
294         boolean easyListEnabled = sharedPreferences.getBoolean("easylist", true);
295         boolean easyPrivacyEnabled = sharedPreferences.getBoolean("easyprivacy", true);
296         boolean fanboyAnnoyanceListEnabled = sharedPreferences.getBoolean("fanboys_annoyance_list", true);
297         boolean fanboySocialBlockingListEnabled = sharedPreferences.getBoolean("fanboys_social_blocking_list", true);
298         boolean ultraPrivacyEnabled = sharedPreferences.getBoolean("ultraprivacy", true);
299         boolean blockAllThirdPartyRequests = sharedPreferences.getBoolean("block_all_third_party_requests", false);
300
301         // Create entries for the database fields.  The ID is created automatically.  The pinned SSL certificate information is not created unless added by the user.
302         domainContentValues.put(DOMAIN_NAME, domainName);
303         domainContentValues.put(ENABLE_JAVASCRIPT, javaScriptEnabled);
304         domainContentValues.put(ENABLE_FIRST_PARTY_COOKIES, firstPartyCookiesEnabled);
305         domainContentValues.put(ENABLE_THIRD_PARTY_COOKIES, thirdPartyCookiesEnabled);
306         domainContentValues.put(ENABLE_DOM_STORAGE, domStorageEnabled);
307         domainContentValues.put(ENABLE_FORM_DATA, saveFormDataEnabled);  // Form data can be removed once the minimum API >= 26.
308         domainContentValues.put(ENABLE_EASYLIST, easyListEnabled);
309         domainContentValues.put(ENABLE_EASYPRIVACY, easyPrivacyEnabled);
310         domainContentValues.put(ENABLE_FANBOYS_ANNOYANCE_LIST, fanboyAnnoyanceListEnabled);
311         domainContentValues.put(ENABLE_FANBOYS_SOCIAL_BLOCKING_LIST, fanboySocialBlockingListEnabled);
312         domainContentValues.put(ENABLE_ULTRAPRIVACY, ultraPrivacyEnabled);
313         domainContentValues.put(BLOCK_ALL_THIRD_PARTY_REQUESTS, blockAllThirdPartyRequests);
314         domainContentValues.put(USER_AGENT, "System default user agent");
315         domainContentValues.put(FONT_SIZE, 0);
316         domainContentValues.put(SWIPE_TO_REFRESH, 0);
317         domainContentValues.put(NIGHT_MODE, 0);
318         domainContentValues.put(DISPLAY_IMAGES, 0);
319
320         // Get a writable database handle.
321         SQLiteDatabase domainsDatabase = this.getWritableDatabase();
322
323         // Insert a new row and store the resulting database ID.  The second argument is `null`, which makes it so that a completely null row cannot be created.
324         int newDomainDatabaseId  = (int) domainsDatabase.insert(DOMAINS_TABLE, null, domainContentValues);
325
326         // Close the database handle.
327         domainsDatabase.close();
328
329         // Return the new domain database ID.
330         return newDomainDatabaseId;
331     }
332
333     void addDomain(ContentValues contentValues) {
334         // Get a writable database handle.
335         SQLiteDatabase domainsDatabase = this.getWritableDatabase();
336
337         // Add the new domain.
338         domainsDatabase.insert(DOMAINS_TABLE, null, contentValues);
339
340         // Close the database handle.
341         domainsDatabase.close();
342     }
343
344     public void updateDomain(int databaseId, String domainName, boolean javaScriptEnabled, boolean firstPartyCookiesEnabled, boolean thirdPartyCookiesEnabled, boolean domStorageEnabled, boolean formDataEnabled,
345                              boolean easyListEnabled, boolean easyPrivacyEnabled, boolean fanboysAnnoyanceEnabled, boolean fanboysSocialBlockingEnabled, boolean ultraPrivacyEnabled,
346                              boolean blockAllThirdPartyRequests, String userAgent, int fontSize, int swipeToRefresh, int nightMode, int displayImages, boolean pinnedSslCertificate, boolean pinnedIpAddresses) {
347
348         // Store the domain data in a `ContentValues`.
349         ContentValues domainContentValues = new ContentValues();
350
351         // Add entries for each field in the database.
352         domainContentValues.put(DOMAIN_NAME, domainName);
353         domainContentValues.put(ENABLE_JAVASCRIPT, javaScriptEnabled);
354         domainContentValues.put(ENABLE_FIRST_PARTY_COOKIES, firstPartyCookiesEnabled);
355         domainContentValues.put(ENABLE_THIRD_PARTY_COOKIES, thirdPartyCookiesEnabled);
356         domainContentValues.put(ENABLE_DOM_STORAGE, domStorageEnabled);
357         domainContentValues.put(ENABLE_FORM_DATA, formDataEnabled);  // Form data can be removed once the minimum API >= 26.
358         domainContentValues.put(ENABLE_EASYLIST, easyListEnabled);
359         domainContentValues.put(ENABLE_EASYPRIVACY, easyPrivacyEnabled);
360         domainContentValues.put(ENABLE_FANBOYS_ANNOYANCE_LIST, fanboysAnnoyanceEnabled);
361         domainContentValues.put(ENABLE_FANBOYS_SOCIAL_BLOCKING_LIST, fanboysSocialBlockingEnabled);
362         domainContentValues.put(ENABLE_ULTRAPRIVACY, ultraPrivacyEnabled);
363         domainContentValues.put(BLOCK_ALL_THIRD_PARTY_REQUESTS, blockAllThirdPartyRequests);
364         domainContentValues.put(USER_AGENT, userAgent);
365         domainContentValues.put(FONT_SIZE, fontSize);
366         domainContentValues.put(SWIPE_TO_REFRESH, swipeToRefresh);
367         domainContentValues.put(NIGHT_MODE, nightMode);
368         domainContentValues.put(DISPLAY_IMAGES, displayImages);
369         domainContentValues.put(PINNED_SSL_CERTIFICATE, pinnedSslCertificate);
370         domainContentValues.put(PINNED_IP_ADDRESSES, pinnedIpAddresses);
371
372         // Get a writable database handle.
373         SQLiteDatabase domainsDatabase = this.getWritableDatabase();
374
375         // Update the row for `databaseId`.  The last argument is `null` because there are no `whereArgs`.
376         domainsDatabase.update(DOMAINS_TABLE, domainContentValues, _ID + " = " + databaseId, null);
377
378         // Close the database handle.
379         domainsDatabase.close();
380     }
381
382     public void updatePinnedSslCertificate(int databaseId, String sslIssuedToCommonName, String sslIssuedToOrganization, String sslIssuedToOrganizationalUnit, String sslIssuedByCommonName,
383                                      String sslIssuedByOrganization, String sslIssuedByOrganizationalUnit, long sslStartDate, long sslEndDate) {
384
385         // Store the pinned SSL certificate in a content values.
386         ContentValues pinnedSslCertificateContentValues = new ContentValues();
387
388         // Add entries for each field in the certificate.
389         pinnedSslCertificateContentValues.put(SSL_ISSUED_TO_COMMON_NAME, sslIssuedToCommonName);
390         pinnedSslCertificateContentValues.put(SSL_ISSUED_TO_ORGANIZATION, sslIssuedToOrganization);
391         pinnedSslCertificateContentValues.put(SSL_ISSUED_TO_ORGANIZATIONAL_UNIT, sslIssuedToOrganizationalUnit);
392         pinnedSslCertificateContentValues.put(SSL_ISSUED_BY_COMMON_NAME, sslIssuedByCommonName);
393         pinnedSslCertificateContentValues.put(SSL_ISSUED_BY_ORGANIZATION, sslIssuedByOrganization);
394         pinnedSslCertificateContentValues.put(SSL_ISSUED_BY_ORGANIZATIONAL_UNIT, sslIssuedByOrganizationalUnit);
395         pinnedSslCertificateContentValues.put(SSL_START_DATE, sslStartDate);
396         pinnedSslCertificateContentValues.put(SSL_END_DATE, sslEndDate);
397
398         // Get a writable database handle.
399         SQLiteDatabase domainsDatabase = this.getWritableDatabase();
400
401         // Update the row for database ID.
402         domainsDatabase.update(DOMAINS_TABLE, pinnedSslCertificateContentValues, _ID + " = " + databaseId, null);
403
404         // Close the database handle.
405         domainsDatabase.close();
406     }
407
408     public void updatePinnedIpAddresses(int databaseId, String ipAddresses) {
409         // Store the pinned IP addresses in a content values.
410         ContentValues pinnedIpAddressesContentValues = new ContentValues();
411
412         // Add the IP addresses to the content values.
413         pinnedIpAddressesContentValues.put(IP_ADDRESSES, ipAddresses);
414
415         // Get a writable database handle.
416         SQLiteDatabase domainsDatabase = this.getWritableDatabase();
417
418         // Update the row for the database ID.
419         domainsDatabase.update(DOMAINS_TABLE, pinnedIpAddressesContentValues, _ID + " = " + databaseId, null);
420
421         // Close the database handle.
422         domainsDatabase.close();
423     }
424
425     public void deleteDomain(int databaseId) {
426         // Get a writable database handle.
427         SQLiteDatabase domainsDatabase = this.getWritableDatabase();
428
429         // Delete the row for `databaseId`.  The last argument is `null` because we don't need additional parameters.
430         domainsDatabase.delete(DOMAINS_TABLE, _ID + " = " + databaseId, null);
431
432         // Close the database handle.
433         domainsDatabase.close();
434     }
435 }