]> gitweb.stoutner.com Git - PrivacyBrowserAndroid.git/blob - app/src/main/java/com/stoutner/privacybrowser/helpers/DomainsDatabaseHelper.java
Add SSL certificate pinning. Implements https://redmine.stoutner.com/issues/54.
[PrivacyBrowserAndroid.git] / app / src / main / java / com / stoutner / privacybrowser / helpers / DomainsDatabaseHelper.java
1 /*
2  * Copyright © 2017 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.database.Cursor;
25 import android.database.sqlite.SQLiteDatabase;
26 import android.database.sqlite.SQLiteOpenHelper;
27
28 public class DomainsDatabaseHelper extends SQLiteOpenHelper {
29     private static final int SCHEMA_VERSION = 3;
30     private static final String DOMAINS_DATABASE = "domains.db";
31     private static final String DOMAINS_TABLE = "domains";
32
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 PINNED_SSL_CERTIFICATE = "pinnedsslcertificate";
44     public static final String SSL_ISSUED_TO_COMMON_NAME = "sslissuedtocommonname";
45     public static final String SSL_ISSUED_TO_ORGANIZATION = "sslissuedtoorganization";
46     public static final String SSL_ISSUED_TO_ORGANIZATIONAL_UNIT = "sslissuedtoorganizationalunit";
47     public static final String SSL_ISSUED_BY_COMMON_NAME = "sslissuedbycommonname";
48     public static final String SSL_ISSUED_BY_ORGANIZATION = "sslissuedbyorganization";
49     public static final String SSL_ISSUED_BY_ORGANIZATIONAL_UNIT = "sslissuedbyorganizationalunit";
50     public static final String SSL_START_DATE = "sslstartdate";
51     public static final String SSL_END_DATE = "sslenddate";
52
53     public static final int DISPLAY_WEBPAGE_IMAGES_SYSTEM_DEFAULT = 0;
54     public static final int DISPLAY_WEBPAGE_IMAGES_ENABLED = 1;
55     public static final int DISPLAY_WEBPAGE_IMAGES_DISABLED = 2;
56
57     // Initialize the database.  The lint warnings for the unused parameters are suppressed.
58     public DomainsDatabaseHelper(Context context, @SuppressWarnings("UnusedParameters") String name, SQLiteDatabase.CursorFactory cursorFactory, @SuppressWarnings("UnusedParameters") int version) {
59         super(context, DOMAINS_DATABASE, cursorFactory, SCHEMA_VERSION);
60     }
61
62     @Override
63     public void onCreate(SQLiteDatabase domainsDatabase) {
64         // Setup the SQL string to create the `domains` table.
65         String CREATE_DOMAINS_TABLE = "CREATE TABLE " + DOMAINS_TABLE + " (" +
66                 _ID + " INTEGER PRIMARY KEY, " +
67                 DOMAIN_NAME + " TEXT, " +
68                 ENABLE_JAVASCRIPT + " BOOLEAN, " +
69                 ENABLE_FIRST_PARTY_COOKIES + " BOOLEAN, " +
70                 ENABLE_THIRD_PARTY_COOKIES + " BOOLEAN, " +
71                 ENABLE_DOM_STORAGE + " BOOLEAN, " +
72                 ENABLE_FORM_DATA + " BOOLEAN, " +
73                 USER_AGENT + " TEXT, " +
74                 FONT_SIZE + " INTEGER, " +
75                 DISPLAY_IMAGES + " INTEGER, " +
76                 PINNED_SSL_CERTIFICATE + " BOOLEAN, " +
77                 SSL_ISSUED_TO_COMMON_NAME + " TEXT, " +
78                 SSL_ISSUED_TO_ORGANIZATION + " TEXT, " +
79                 SSL_ISSUED_TO_ORGANIZATIONAL_UNIT + " TEXT, " +
80                 SSL_ISSUED_BY_COMMON_NAME + " TEXT, " +
81                 SSL_ISSUED_BY_ORGANIZATION + " TEXT, " +
82                 SSL_ISSUED_BY_ORGANIZATIONAL_UNIT + " TEXT, " +
83                 SSL_START_DATE + " INTEGER, " +
84                 SSL_END_DATE + " INTEGER);";
85
86         // Make it so.
87         domainsDatabase.execSQL(CREATE_DOMAINS_TABLE);
88     }
89
90     @Override
91     public void onUpgrade(SQLiteDatabase domainsDatabase, int oldVersion, int newVersion) {
92         // Upgrade `DOMAINS_TABLE`.
93         switch (oldVersion) {
94             // Upgrade from `SCHEMA_VERSION` 1.
95             case 1:
96                 // Add the `DISPLAY_IMAGES` column.
97                 domainsDatabase.execSQL("ALTER TABLE " + DOMAINS_TABLE + " ADD COLUMN " + DISPLAY_IMAGES + " INTEGER");
98
99             // Upgrade from `SCHEMA_VERSION` 2.
100             case 2:
101                 //  Add the SSL certificate columns.
102                 domainsDatabase.execSQL("ALTER TABLE " + DOMAINS_TABLE + " ADD COLUMN " + PINNED_SSL_CERTIFICATE + " BOOLEAN");
103                 domainsDatabase.execSQL("ALTER TABLE " + DOMAINS_TABLE + " ADD COLUMN " + SSL_ISSUED_TO_COMMON_NAME + " TEXT");
104                 domainsDatabase.execSQL("ALTER TABLE " + DOMAINS_TABLE + " ADD COLUMN " + SSL_ISSUED_TO_ORGANIZATION + " TEXT");
105                 domainsDatabase.execSQL("ALTER TABLE " + DOMAINS_TABLE + " ADD COLUMN " + SSL_ISSUED_TO_ORGANIZATIONAL_UNIT + " TEXT");
106                 domainsDatabase.execSQL("ALTER TABLE " + DOMAINS_TABLE + " ADD COLUMN " + SSL_ISSUED_BY_COMMON_NAME + " TEXT");
107                 domainsDatabase.execSQL("ALTER TABLE " + DOMAINS_TABLE + " ADD COLUMN " + SSL_ISSUED_BY_ORGANIZATION + " TEXT");
108                 domainsDatabase.execSQL("ALTER TABLE " + DOMAINS_TABLE + " ADD COLUMN " + SSL_ISSUED_BY_ORGANIZATIONAL_UNIT + " TEXT");
109                 domainsDatabase.execSQL("ALTER TABLE " + DOMAINS_TABLE + " ADD COLUMN " + SSL_START_DATE + " INTEGER");
110                 domainsDatabase.execSQL("ALTER TABLE " + DOMAINS_TABLE + " ADD COLUMN " + SSL_END_DATE + " INTEGER");
111         }
112     }
113
114     public Cursor getDomainNameCursorOrderedByDomain() {
115         // Get a readable database handle.
116         SQLiteDatabase domainsDatabase = this.getReadableDatabase();
117
118         // Get everything in `DOMAINS_TABLE` ordered by `DOMAIN_NAME`.
119         final String GET_CURSOR_ORDERED_BY_DOMAIN = "SELECT " + _ID + ", " + DOMAIN_NAME +
120                 " FROM " + DOMAINS_TABLE +
121                 " ORDER BY " + DOMAIN_NAME + " ASC";
122
123         // 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.
124         return domainsDatabase.rawQuery(GET_CURSOR_ORDERED_BY_DOMAIN, null);
125     }
126
127     public Cursor getDomainNameCursorOrderedByDomainExcept(int databaseId) {
128         // Get a readable database handle.
129         SQLiteDatabase domainsDatabase = this.getReadableDatabase();
130
131         // Prepare the SQL statement to select all rows except that with `databaseId`.
132         final String GET_CURSOR_ORDERED_BY_DOMAIN_EXCEPT = "SELECT " + _ID + ", " + DOMAIN_NAME +
133                 " FROM " + DOMAINS_TABLE +
134                 " WHERE " + _ID + " IS NOT " + databaseId +
135                 " ORDER BY " + DOMAIN_NAME + " ASC";
136
137         // 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.
138         return domainsDatabase.rawQuery(GET_CURSOR_ORDERED_BY_DOMAIN_EXCEPT, null);
139     }
140
141     public Cursor getCursorForId(int databaseId) {
142         // Get a readable database handle.
143         SQLiteDatabase domainsDatabase = this.getReadableDatabase();
144
145         // Prepare the SQL statement to get the `Cursor` for `databaseId`.
146         final String GET_CURSOR_FOR_ID = "SELECT * FROM " + DOMAINS_TABLE +
147                 " WHERE " + _ID + " = " + databaseId;
148
149         // 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.
150         return domainsDatabase.rawQuery(GET_CURSOR_FOR_ID, null);
151     }
152
153     public Cursor getCursorForDomainName(String domainName) {
154         // Get a readable database handle.
155         SQLiteDatabase domainsDatabase = this.getReadableDatabase();
156
157         // Prepare the SQL statement to get the `Cursor` for `domainName`.
158         final String GET_CURSOR_FOR_DOMAIN_NAME = "SELECT * FROM " + DOMAINS_TABLE +
159                 " WHERE " + DOMAIN_NAME + " = " + "\"" + domainName + "\"";
160
161         // 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.
162         return domainsDatabase.rawQuery(GET_CURSOR_FOR_DOMAIN_NAME, null);
163     }
164
165     public int addDomain(String domainName) {
166         // Store the domain data in a `ContentValues`.
167         ContentValues domainContentValues = new ContentValues();
168
169         // Create entries for each field in the database.  The ID is created automatically.
170         domainContentValues.put(DOMAIN_NAME, domainName);
171         domainContentValues.put(ENABLE_JAVASCRIPT, false);
172         domainContentValues.put(ENABLE_FIRST_PARTY_COOKIES, false);
173         domainContentValues.put(ENABLE_THIRD_PARTY_COOKIES, false);
174         domainContentValues.put(ENABLE_DOM_STORAGE, false);
175         domainContentValues.put(ENABLE_FORM_DATA, false);
176         domainContentValues.put(USER_AGENT, "System default user agent");
177         domainContentValues.put(FONT_SIZE, 0);
178         domainContentValues.put(DISPLAY_IMAGES, 0);
179
180         // Get a writable database handle.
181         SQLiteDatabase domainsDatabase = this.getWritableDatabase();
182
183         // 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.
184         int newDomainDatabaseId  = (int) domainsDatabase.insert(DOMAINS_TABLE, null, domainContentValues);
185
186         // Close the database handle.
187         domainsDatabase.close();
188
189         return newDomainDatabaseId;
190     }
191
192     public void updateDomainExceptCertificate(int databaseId, String domainName, boolean javaScriptEnabled, boolean firstPartyCookiesEnabled, boolean thirdPartyCookiesEnabled, boolean domStorageEnabled, boolean formDataEnabled, String userAgent, int fontSize,
193                                               int displayImages, boolean pinnedSslCertificate) {
194         // Store the domain data in a `ContentValues`.
195         ContentValues domainContentValues = new ContentValues();
196
197         // Add entries for each field in the database.
198         domainContentValues.put(DOMAIN_NAME, domainName);
199         domainContentValues.put(ENABLE_JAVASCRIPT, javaScriptEnabled);
200         domainContentValues.put(ENABLE_FIRST_PARTY_COOKIES, firstPartyCookiesEnabled);
201         domainContentValues.put(ENABLE_THIRD_PARTY_COOKIES, thirdPartyCookiesEnabled);
202         domainContentValues.put(ENABLE_DOM_STORAGE, domStorageEnabled);
203         domainContentValues.put(ENABLE_FORM_DATA, formDataEnabled);
204         domainContentValues.put(USER_AGENT, userAgent);
205         domainContentValues.put(FONT_SIZE, fontSize);
206         domainContentValues.put(DISPLAY_IMAGES, displayImages);
207         domainContentValues.put(PINNED_SSL_CERTIFICATE, pinnedSslCertificate);
208
209         // Get a writable database handle.
210         SQLiteDatabase domainsDatabase = this.getWritableDatabase();
211
212         // Update the row for `databaseId`.  The last argument is `null` because there are no `whereArgs`.
213         domainsDatabase.update(DOMAINS_TABLE, domainContentValues, _ID + " = " + databaseId, null);
214
215         // Close the database handle.
216         domainsDatabase.close();
217     }
218
219     public void updateDomainWithCertificate(int databaseId, String domainName, boolean javaScriptEnabled, boolean firstPartyCookiesEnabled, boolean thirdPartyCookiesEnabled, boolean domStorageEnabled, boolean formDataEnabled, String userAgent, int fontSize,
220                                             int displayImages, boolean pinnedSslCertificate, String sslIssuedToCommonName, String sslIssuedToOrganization, String sslIssuedToOrganizationalUnit, String sslIssuedByCommonName, String sslIssuedByOrganization,
221                                             String sslIssuedByOrganizationalUnit, long sslStartDate, long sslEndDate) {
222         // Store the domain data in a `ContentValues`.
223         ContentValues domainContentValues = new ContentValues();
224
225         // Add entries for each field in the database.
226         domainContentValues.put(DOMAIN_NAME, domainName);
227         domainContentValues.put(ENABLE_JAVASCRIPT, javaScriptEnabled);
228         domainContentValues.put(ENABLE_FIRST_PARTY_COOKIES, firstPartyCookiesEnabled);
229         domainContentValues.put(ENABLE_THIRD_PARTY_COOKIES, thirdPartyCookiesEnabled);
230         domainContentValues.put(ENABLE_DOM_STORAGE, domStorageEnabled);
231         domainContentValues.put(ENABLE_FORM_DATA, formDataEnabled);
232         domainContentValues.put(USER_AGENT, userAgent);
233         domainContentValues.put(FONT_SIZE, fontSize);
234         domainContentValues.put(DISPLAY_IMAGES, displayImages);
235         domainContentValues.put(PINNED_SSL_CERTIFICATE, pinnedSslCertificate);
236         domainContentValues.put(SSL_ISSUED_TO_COMMON_NAME, sslIssuedToCommonName);
237         domainContentValues.put(SSL_ISSUED_TO_ORGANIZATION, sslIssuedToOrganization);
238         domainContentValues.put(SSL_ISSUED_TO_ORGANIZATIONAL_UNIT, sslIssuedToOrganizationalUnit);
239         domainContentValues.put(SSL_ISSUED_BY_COMMON_NAME, sslIssuedByCommonName);
240         domainContentValues.put(SSL_ISSUED_BY_ORGANIZATION, sslIssuedByOrganization);
241         domainContentValues.put(SSL_ISSUED_BY_ORGANIZATIONAL_UNIT, sslIssuedByOrganizationalUnit);
242         domainContentValues.put(SSL_START_DATE, sslStartDate);
243         domainContentValues.put(SSL_END_DATE, sslEndDate);
244
245         // Get a writable database handle.
246         SQLiteDatabase domainsDatabase = this.getWritableDatabase();
247
248         // Update the row for `databaseId`.  The last argument is `null` because there are no `whereArgs`.
249         domainsDatabase.update(DOMAINS_TABLE, domainContentValues, _ID + " = " + databaseId, null);
250
251         // Close the database handle.
252         domainsDatabase.close();
253     }
254
255     public void updateCertificate(int databaseId, String sslIssuedToCommonName, String sslIssuedToOrganization, String sslIssuedToOrganizationalUnit, String sslIssuedByCommonName, String sslIssuedByOrganization, String sslIssuedByOrganizationalUnit,
256                                   long sslStartDate, long sslEndDate) {
257         // Store the domain data in a `ContentValues`.
258         ContentValues domainContentValues = new ContentValues();
259
260         // Add entries for each field in the certificate.
261         domainContentValues.put(SSL_ISSUED_TO_COMMON_NAME, sslIssuedToCommonName);
262         domainContentValues.put(SSL_ISSUED_TO_ORGANIZATION, sslIssuedToOrganization);
263         domainContentValues.put(SSL_ISSUED_TO_ORGANIZATIONAL_UNIT, sslIssuedToOrganizationalUnit);
264         domainContentValues.put(SSL_ISSUED_BY_COMMON_NAME, sslIssuedByCommonName);
265         domainContentValues.put(SSL_ISSUED_BY_ORGANIZATION, sslIssuedByOrganization);
266         domainContentValues.put(SSL_ISSUED_BY_ORGANIZATIONAL_UNIT, sslIssuedByOrganizationalUnit);
267         domainContentValues.put(SSL_START_DATE, sslStartDate);
268         domainContentValues.put(SSL_END_DATE, sslEndDate);
269
270         // Get a writable database handle.
271         SQLiteDatabase domainsDatabase = this.getWritableDatabase();
272
273         // Update the row for `databaseId`.  The last argument is `null` because there are no `whereArgs`.
274         domainsDatabase.update(DOMAINS_TABLE, domainContentValues, _ID + " = " + databaseId, null);
275
276         // Close the database handle.
277         domainsDatabase.close();
278     }
279
280     public void deleteDomain(int databaseId) {
281         // Get a writable database handle.
282         SQLiteDatabase domainsDatabase = this.getWritableDatabase();
283
284         // Delete the row for `databaseId`.  The last argument is `null` because we don't need additional parameters.
285         domainsDatabase.delete(DOMAINS_TABLE, _ID + " = " + databaseId, null);
286
287         // Close the database handle.
288         domainsDatabase.close();
289     }
290 }