2 * Copyright © 2017 Soren Stoutner <soren@stoutner.com>.
4 * This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
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.
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.
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/>.
20 package com.stoutner.privacybrowser.helpers;
22 import android.content.ContentValues;
23 import android.content.Context;
24 import android.database.Cursor;
25 import android.database.sqlite.SQLiteDatabase;
26 import android.database.sqlite.SQLiteOpenHelper;
28 public class DomainsDatabaseHelper extends SQLiteOpenHelper {
29 private static final int SCHEMA_VERSION = 4;
30 private static final String DOMAINS_DATABASE = "domains.db";
31 private static final String DOMAINS_TABLE = "domains";
33 public static final String _ID = "_id";
34 public static final String DOMAIN_NAME = "domainname";
35 public static final String ENABLE_JAVASCRIPT = "enablejavascript";
36 public static final String ENABLE_FIRST_PARTY_COOKIES = "enablefirstpartycookies";
37 public static final String ENABLE_THIRD_PARTY_COOKIES = "enablethirdpartycookies";
38 public static final String ENABLE_DOM_STORAGE = "enabledomstorage";
39 public static final String ENABLE_FORM_DATA = "enableformdata";
40 public static final String USER_AGENT = "useragent";
41 public static final String FONT_SIZE = "fontsize";
42 public static final String DISPLAY_IMAGES = "displayimages";
43 public static final String NIGHT_MODE = "nightmode";
44 public static final String PINNED_SSL_CERTIFICATE = "pinnedsslcertificate";
45 public static final String SSL_ISSUED_TO_COMMON_NAME = "sslissuedtocommonname";
46 public static final String SSL_ISSUED_TO_ORGANIZATION = "sslissuedtoorganization";
47 public static final String SSL_ISSUED_TO_ORGANIZATIONAL_UNIT = "sslissuedtoorganizationalunit";
48 public static final String SSL_ISSUED_BY_COMMON_NAME = "sslissuedbycommonname";
49 public static final String SSL_ISSUED_BY_ORGANIZATION = "sslissuedbyorganization";
50 public static final String SSL_ISSUED_BY_ORGANIZATIONAL_UNIT = "sslissuedbyorganizationalunit";
51 public static final String SSL_START_DATE = "sslstartdate";
52 public static final String SSL_END_DATE = "sslenddate";
54 // Display webpage images constants.
55 public static final int DISPLAY_WEBPAGE_IMAGES_SYSTEM_DEFAULT = 0;
56 public static final int DISPLAY_WEBPAGE_IMAGES_ENABLED = 1;
57 public static final int DISPLAY_WEBPAGE_IMAGES_DISABLED = 2;
59 // Night mode constants.
60 public static final int NIGHT_MODE_SYSTEM_DEFAULT = 0;
61 public static final int NIGHT_MODE_ENABLED = 1;
62 public static final int NIGHT_MODE_DISABLED = 2;
64 // Initialize the database. The lint warnings for the unused parameters are suppressed.
65 public DomainsDatabaseHelper(Context context, @SuppressWarnings("UnusedParameters") String name, SQLiteDatabase.CursorFactory cursorFactory, @SuppressWarnings("UnusedParameters") int version) {
66 super(context, DOMAINS_DATABASE, cursorFactory, SCHEMA_VERSION);
70 public void onCreate(SQLiteDatabase domainsDatabase) {
71 // Setup the SQL string to create the `domains` table.
72 String CREATE_DOMAINS_TABLE = "CREATE TABLE " + DOMAINS_TABLE + " (" +
73 _ID + " INTEGER PRIMARY KEY, " +
74 DOMAIN_NAME + " TEXT, " +
75 ENABLE_JAVASCRIPT + " BOOLEAN, " +
76 ENABLE_FIRST_PARTY_COOKIES + " BOOLEAN, " +
77 ENABLE_THIRD_PARTY_COOKIES + " BOOLEAN, " +
78 ENABLE_DOM_STORAGE + " BOOLEAN, " +
79 ENABLE_FORM_DATA + " BOOLEAN, " +
80 USER_AGENT + " TEXT, " +
81 FONT_SIZE + " INTEGER, " +
82 DISPLAY_IMAGES + " INTEGER, " +
83 NIGHT_MODE + " INTEGER, " +
84 PINNED_SSL_CERTIFICATE + " BOOLEAN, " +
85 SSL_ISSUED_TO_COMMON_NAME + " TEXT, " +
86 SSL_ISSUED_TO_ORGANIZATION + " TEXT, " +
87 SSL_ISSUED_TO_ORGANIZATIONAL_UNIT + " TEXT, " +
88 SSL_ISSUED_BY_COMMON_NAME + " TEXT, " +
89 SSL_ISSUED_BY_ORGANIZATION + " TEXT, " +
90 SSL_ISSUED_BY_ORGANIZATIONAL_UNIT + " TEXT, " +
91 SSL_START_DATE + " INTEGER, " +
92 SSL_END_DATE + " INTEGER);";
95 domainsDatabase.execSQL(CREATE_DOMAINS_TABLE);
99 public void onUpgrade(SQLiteDatabase domainsDatabase, int oldVersion, int newVersion) {
100 // Upgrade `DOMAINS_TABLE`.
101 switch (oldVersion) {
102 // Upgrade from `SCHEMA_VERSION` 1.
104 // Add the `DISPLAY_IMAGES` column.
105 domainsDatabase.execSQL("ALTER TABLE " + DOMAINS_TABLE + " ADD COLUMN " + DISPLAY_IMAGES + " INTEGER");
107 // Upgrade from `SCHEMA_VERSION` 2.
109 // Add the SSL certificate columns.
110 domainsDatabase.execSQL("ALTER TABLE " + DOMAINS_TABLE + " ADD COLUMN " + PINNED_SSL_CERTIFICATE + " BOOLEAN");
111 domainsDatabase.execSQL("ALTER TABLE " + DOMAINS_TABLE + " ADD COLUMN " + SSL_ISSUED_TO_COMMON_NAME + " TEXT");
112 domainsDatabase.execSQL("ALTER TABLE " + DOMAINS_TABLE + " ADD COLUMN " + SSL_ISSUED_TO_ORGANIZATION + " TEXT");
113 domainsDatabase.execSQL("ALTER TABLE " + DOMAINS_TABLE + " ADD COLUMN " + SSL_ISSUED_TO_ORGANIZATIONAL_UNIT + " TEXT");
114 domainsDatabase.execSQL("ALTER TABLE " + DOMAINS_TABLE + " ADD COLUMN " + SSL_ISSUED_BY_COMMON_NAME + " TEXT");
115 domainsDatabase.execSQL("ALTER TABLE " + DOMAINS_TABLE + " ADD COLUMN " + SSL_ISSUED_BY_ORGANIZATION + " TEXT");
116 domainsDatabase.execSQL("ALTER TABLE " + DOMAINS_TABLE + " ADD COLUMN " + SSL_ISSUED_BY_ORGANIZATIONAL_UNIT + " TEXT");
117 domainsDatabase.execSQL("ALTER TABLE " + DOMAINS_TABLE + " ADD COLUMN " + SSL_START_DATE + " INTEGER");
118 domainsDatabase.execSQL("ALTER TABLE " + DOMAINS_TABLE + " ADD COLUMN " + SSL_END_DATE + " INTEGER");
120 // Upgrade from `SCHEMA_VERSION` 3.
122 // Add the `NIGHT_MODE` column.
123 domainsDatabase.execSQL("ALTER TABLE " + DOMAINS_TABLE + " ADD COLUMN " + NIGHT_MODE + " INTEGER");
127 public Cursor getDomainNameCursorOrderedByDomain() {
128 // Get a readable database handle.
129 SQLiteDatabase domainsDatabase = this.getReadableDatabase();
131 // Get everything in `DOMAINS_TABLE` ordered by `DOMAIN_NAME`.
132 final String GET_CURSOR_ORDERED_BY_DOMAIN = "SELECT " + _ID + ", " + DOMAIN_NAME +
133 " FROM " + DOMAINS_TABLE +
134 " ORDER BY " + DOMAIN_NAME + " ASC";
136 // Return the results as a `Cursor`. The second argument is `null` because there are no `selectionArgs`. We can't close the `Cursor` because we need to use it in the parent activity.
137 return domainsDatabase.rawQuery(GET_CURSOR_ORDERED_BY_DOMAIN, null);
140 public Cursor getDomainNameCursorOrderedByDomainExcept(int databaseId) {
141 // Get a readable database handle.
142 SQLiteDatabase domainsDatabase = this.getReadableDatabase();
144 // Prepare the SQL statement to select all rows except that with `databaseId`.
145 final String GET_CURSOR_ORDERED_BY_DOMAIN_EXCEPT = "SELECT " + _ID + ", " + DOMAIN_NAME +
146 " FROM " + DOMAINS_TABLE +
147 " WHERE " + _ID + " IS NOT " + databaseId +
148 " ORDER BY " + DOMAIN_NAME + " ASC";
150 // Return the results as a `Cursor`. The second argument is `null` because there are no `selectionArgs`. We can't close the `Cursor` because we need to use it in the calling activity.
151 return domainsDatabase.rawQuery(GET_CURSOR_ORDERED_BY_DOMAIN_EXCEPT, null);
154 public Cursor getCursorForId(int databaseId) {
155 // Get a readable database handle.
156 SQLiteDatabase domainsDatabase = this.getReadableDatabase();
158 // Prepare the SQL statement to get the `Cursor` for `databaseId`.
159 final String GET_CURSOR_FOR_ID = "SELECT * FROM " + DOMAINS_TABLE +
160 " WHERE " + _ID + " = " + databaseId;
162 // Return the results as a `Cursor`. The second argument is `null` because there are no `selectionArgs`. We can't close the `Cursor` because we need to use it in the calling activity.
163 return domainsDatabase.rawQuery(GET_CURSOR_FOR_ID, null);
166 public Cursor getCursorForDomainName(String domainName) {
167 // Get a readable database handle.
168 SQLiteDatabase domainsDatabase = this.getReadableDatabase();
170 // Prepare the SQL statement to get the `Cursor` for `domainName`.
171 final String GET_CURSOR_FOR_DOMAIN_NAME = "SELECT * FROM " + DOMAINS_TABLE +
172 " WHERE " + DOMAIN_NAME + " = " + "\"" + domainName + "\"";
174 // Return the results as a `Cursor`. The second argument is `null` because there are no `selectionArgs`. We can't close the `Cursor` because we need to us it in the calling activity.
175 return domainsDatabase.rawQuery(GET_CURSOR_FOR_DOMAIN_NAME, null);
178 public int addDomain(String domainName) {
179 // Store the domain data in a `ContentValues`.
180 ContentValues domainContentValues = new ContentValues();
182 // Create entries for the database fields. The ID is created automatically. The pinned SSL certificate information is not created unless added by the user.
183 domainContentValues.put(DOMAIN_NAME, domainName);
184 domainContentValues.put(ENABLE_JAVASCRIPT, false);
185 domainContentValues.put(ENABLE_FIRST_PARTY_COOKIES, false);
186 domainContentValues.put(ENABLE_THIRD_PARTY_COOKIES, false);
187 domainContentValues.put(ENABLE_DOM_STORAGE, false);
188 domainContentValues.put(ENABLE_FORM_DATA, false);
189 domainContentValues.put(USER_AGENT, "System default user agent");
190 domainContentValues.put(FONT_SIZE, 0);
191 domainContentValues.put(DISPLAY_IMAGES, 0);
192 domainContentValues.put(NIGHT_MODE, 0);
194 // Get a writable database handle.
195 SQLiteDatabase domainsDatabase = this.getWritableDatabase();
197 // 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.
198 int newDomainDatabaseId = (int) domainsDatabase.insert(DOMAINS_TABLE, null, domainContentValues);
200 // Close the database handle.
201 domainsDatabase.close();
203 // Return the new domain database ID.
204 return newDomainDatabaseId;
207 public void updateDomainExceptCertificate(int databaseId, String domainName, boolean javaScriptEnabled, boolean firstPartyCookiesEnabled, boolean thirdPartyCookiesEnabled, boolean domStorageEnabled, boolean formDataEnabled, String userAgent, int fontSize,
208 int displayImages, int nightMode, boolean pinnedSslCertificate) {
209 // Store the domain data in a `ContentValues`.
210 ContentValues domainContentValues = new ContentValues();
212 // Add entries for each field in the database.
213 domainContentValues.put(DOMAIN_NAME, domainName);
214 domainContentValues.put(ENABLE_JAVASCRIPT, javaScriptEnabled);
215 domainContentValues.put(ENABLE_FIRST_PARTY_COOKIES, firstPartyCookiesEnabled);
216 domainContentValues.put(ENABLE_THIRD_PARTY_COOKIES, thirdPartyCookiesEnabled);
217 domainContentValues.put(ENABLE_DOM_STORAGE, domStorageEnabled);
218 domainContentValues.put(ENABLE_FORM_DATA, formDataEnabled);
219 domainContentValues.put(USER_AGENT, userAgent);
220 domainContentValues.put(FONT_SIZE, fontSize);
221 domainContentValues.put(DISPLAY_IMAGES, displayImages);
222 domainContentValues.put(NIGHT_MODE, nightMode);
223 domainContentValues.put(PINNED_SSL_CERTIFICATE, pinnedSslCertificate);
225 // Get a writable database handle.
226 SQLiteDatabase domainsDatabase = this.getWritableDatabase();
228 // Update the row for `databaseId`. The last argument is `null` because there are no `whereArgs`.
229 domainsDatabase.update(DOMAINS_TABLE, domainContentValues, _ID + " = " + databaseId, null);
231 // Close the database handle.
232 domainsDatabase.close();
235 public void updateDomainWithCertificate(int databaseId, String domainName, boolean javaScriptEnabled, boolean firstPartyCookiesEnabled, boolean thirdPartyCookiesEnabled, boolean domStorageEnabled, boolean formDataEnabled, String userAgent, int fontSize,
236 int displayImages, int nightMode, boolean pinnedSslCertificate, String sslIssuedToCommonName, String sslIssuedToOrganization, String sslIssuedToOrganizationalUnit, String sslIssuedByCommonName, String sslIssuedByOrganization,
237 String sslIssuedByOrganizationalUnit, long sslStartDate, long sslEndDate) {
238 // Store the domain data in a `ContentValues`.
239 ContentValues domainContentValues = new ContentValues();
241 // Add entries for each field in the database.
242 domainContentValues.put(DOMAIN_NAME, domainName);
243 domainContentValues.put(ENABLE_JAVASCRIPT, javaScriptEnabled);
244 domainContentValues.put(ENABLE_FIRST_PARTY_COOKIES, firstPartyCookiesEnabled);
245 domainContentValues.put(ENABLE_THIRD_PARTY_COOKIES, thirdPartyCookiesEnabled);
246 domainContentValues.put(ENABLE_DOM_STORAGE, domStorageEnabled);
247 domainContentValues.put(ENABLE_FORM_DATA, formDataEnabled);
248 domainContentValues.put(USER_AGENT, userAgent);
249 domainContentValues.put(FONT_SIZE, fontSize);
250 domainContentValues.put(DISPLAY_IMAGES, displayImages);
251 domainContentValues.put(NIGHT_MODE, nightMode);
252 domainContentValues.put(PINNED_SSL_CERTIFICATE, pinnedSslCertificate);
253 domainContentValues.put(SSL_ISSUED_TO_COMMON_NAME, sslIssuedToCommonName);
254 domainContentValues.put(SSL_ISSUED_TO_ORGANIZATION, sslIssuedToOrganization);
255 domainContentValues.put(SSL_ISSUED_TO_ORGANIZATIONAL_UNIT, sslIssuedToOrganizationalUnit);
256 domainContentValues.put(SSL_ISSUED_BY_COMMON_NAME, sslIssuedByCommonName);
257 domainContentValues.put(SSL_ISSUED_BY_ORGANIZATION, sslIssuedByOrganization);
258 domainContentValues.put(SSL_ISSUED_BY_ORGANIZATIONAL_UNIT, sslIssuedByOrganizationalUnit);
259 domainContentValues.put(SSL_START_DATE, sslStartDate);
260 domainContentValues.put(SSL_END_DATE, sslEndDate);
262 // Get a writable database handle.
263 SQLiteDatabase domainsDatabase = this.getWritableDatabase();
265 // Update the row for `databaseId`. The last argument is `null` because there are no `whereArgs`.
266 domainsDatabase.update(DOMAINS_TABLE, domainContentValues, _ID + " = " + databaseId, null);
268 // Close the database handle.
269 domainsDatabase.close();
272 public void updateCertificate(int databaseId, String sslIssuedToCommonName, String sslIssuedToOrganization, String sslIssuedToOrganizationalUnit, String sslIssuedByCommonName, String sslIssuedByOrganization, String sslIssuedByOrganizationalUnit,
273 long sslStartDate, long sslEndDate) {
274 // Store the domain data in a `ContentValues`.
275 ContentValues domainContentValues = new ContentValues();
277 // Add entries for each field in the certificate.
278 domainContentValues.put(SSL_ISSUED_TO_COMMON_NAME, sslIssuedToCommonName);
279 domainContentValues.put(SSL_ISSUED_TO_ORGANIZATION, sslIssuedToOrganization);
280 domainContentValues.put(SSL_ISSUED_TO_ORGANIZATIONAL_UNIT, sslIssuedToOrganizationalUnit);
281 domainContentValues.put(SSL_ISSUED_BY_COMMON_NAME, sslIssuedByCommonName);
282 domainContentValues.put(SSL_ISSUED_BY_ORGANIZATION, sslIssuedByOrganization);
283 domainContentValues.put(SSL_ISSUED_BY_ORGANIZATIONAL_UNIT, sslIssuedByOrganizationalUnit);
284 domainContentValues.put(SSL_START_DATE, sslStartDate);
285 domainContentValues.put(SSL_END_DATE, sslEndDate);
287 // Get a writable database handle.
288 SQLiteDatabase domainsDatabase = this.getWritableDatabase();
290 // Update the row for `databaseId`. The last argument is `null` because there are no `whereArgs`.
291 domainsDatabase.update(DOMAINS_TABLE, domainContentValues, _ID + " = " + databaseId, null);
293 // Close the database handle.
294 domainsDatabase.close();
297 public void deleteDomain(int databaseId) {
298 // Get a writable database handle.
299 SQLiteDatabase domainsDatabase = this.getWritableDatabase();
301 // Delete the row for `databaseId`. The last argument is `null` because we don't need additional parameters.
302 domainsDatabase.delete(DOMAINS_TABLE, _ID + " = " + databaseId, null);
304 // Close the database handle.
305 domainsDatabase.close();