android: Add property for included subnets to VPN profiles
[strongswan.git] / src / frontends / android / app / src / main / java / org / strongswan / android / data / VpnProfileDataSource.java
1 /*
2 * Copyright (C) 2012-2017 Tobias Brunner
3 * Copyright (C) 2012 Giuliano Grassi
4 * Copyright (C) 2012 Ralf Sager
5 * HSR Hochschule fuer Technik Rapperswil
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 * for more details.
16 */
17
18 package org.strongswan.android.data;
19
20 import android.content.ContentValues;
21 import android.content.Context;
22 import android.database.Cursor;
23 import android.database.SQLException;
24 import android.database.sqlite.SQLiteDatabase;
25 import android.database.sqlite.SQLiteOpenHelper;
26 import android.database.sqlite.SQLiteQueryBuilder;
27 import android.util.Log;
28
29 import java.util.ArrayList;
30 import java.util.List;
31 import java.util.UUID;
32
33 public class VpnProfileDataSource
34 {
35 private static final String TAG = VpnProfileDataSource.class.getSimpleName();
36 public static final String KEY_ID = "_id";
37 public static final String KEY_UUID = "_uuid";
38 public static final String KEY_NAME = "name";
39 public static final String KEY_GATEWAY = "gateway";
40 public static final String KEY_VPN_TYPE = "vpn_type";
41 public static final String KEY_USERNAME = "username";
42 public static final String KEY_PASSWORD = "password";
43 public static final String KEY_CERTIFICATE = "certificate";
44 public static final String KEY_USER_CERTIFICATE = "user_certificate";
45 public static final String KEY_MTU = "mtu";
46 public static final String KEY_PORT = "port";
47 public static final String KEY_SPLIT_TUNNELING = "split_tunneling";
48 public static final String KEY_LOCAL_ID = "local_id";
49 public static final String KEY_REMOTE_ID = "remote_id";
50 public static final String KEY_EXCLUDED_SUBNETS = "excluded_subnets";
51 public static final String KEY_INCLUDED_SUBNETS = "included_subnets";
52
53 private DatabaseHelper mDbHelper;
54 private SQLiteDatabase mDatabase;
55 private final Context mContext;
56
57 private static final String DATABASE_NAME = "strongswan.db";
58 private static final String TABLE_VPNPROFILE = "vpnprofile";
59
60 private static final int DATABASE_VERSION = 11;
61
62 public static final String DATABASE_CREATE =
63 "CREATE TABLE " + TABLE_VPNPROFILE + " (" +
64 KEY_ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
65 KEY_UUID + " TEXT UNIQUE," +
66 KEY_NAME + " TEXT NOT NULL," +
67 KEY_GATEWAY + " TEXT NOT NULL," +
68 KEY_VPN_TYPE + " TEXT NOT NULL," +
69 KEY_USERNAME + " TEXT," +
70 KEY_PASSWORD + " TEXT," +
71 KEY_CERTIFICATE + " TEXT," +
72 KEY_USER_CERTIFICATE + " TEXT," +
73 KEY_MTU + " INTEGER," +
74 KEY_PORT + " INTEGER," +
75 KEY_SPLIT_TUNNELING + " INTEGER," +
76 KEY_LOCAL_ID + " TEXT," +
77 KEY_REMOTE_ID + " TEXT," +
78 KEY_EXCLUDED_SUBNETS + " TEXT," +
79 KEY_INCLUDED_SUBNETS + " TEXT" +
80 ");";
81 private static final String[] ALL_COLUMNS = new String[] {
82 KEY_ID,
83 KEY_UUID,
84 KEY_NAME,
85 KEY_GATEWAY,
86 KEY_VPN_TYPE,
87 KEY_USERNAME,
88 KEY_PASSWORD,
89 KEY_CERTIFICATE,
90 KEY_USER_CERTIFICATE,
91 KEY_MTU,
92 KEY_PORT,
93 KEY_SPLIT_TUNNELING,
94 KEY_LOCAL_ID,
95 KEY_REMOTE_ID,
96 KEY_EXCLUDED_SUBNETS,
97 KEY_INCLUDED_SUBNETS,
98 };
99
100 private static class DatabaseHelper extends SQLiteOpenHelper
101 {
102 public DatabaseHelper(Context context)
103 {
104 super(context, DATABASE_NAME, null, DATABASE_VERSION);
105 }
106
107 @Override
108 public void onCreate(SQLiteDatabase database)
109 {
110 database.execSQL(DATABASE_CREATE);
111 }
112
113 @Override
114 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
115 {
116 Log.w(TAG, "Upgrading database from version " + oldVersion +
117 " to " + newVersion);
118 if (oldVersion < 2)
119 {
120 db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " ADD " + KEY_USER_CERTIFICATE +
121 " TEXT;");
122 }
123 if (oldVersion < 3)
124 {
125 db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " ADD " + KEY_VPN_TYPE +
126 " TEXT DEFAULT '';");
127 }
128 if (oldVersion < 4)
129 { /* remove NOT NULL constraint from username column */
130 updateColumns(db);
131 }
132 if (oldVersion < 5)
133 {
134 db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " ADD " + KEY_MTU +
135 " INTEGER;");
136 }
137 if (oldVersion < 6)
138 {
139 db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " ADD " + KEY_PORT +
140 " INTEGER;");
141 }
142 if (oldVersion < 7)
143 {
144 db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " ADD " + KEY_SPLIT_TUNNELING +
145 " INTEGER;");
146 }
147 if (oldVersion < 8)
148 {
149 db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " ADD " + KEY_LOCAL_ID +
150 " TEXT;");
151 db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " ADD " + KEY_REMOTE_ID +
152 " TEXT;");
153 }
154 if (oldVersion < 9)
155 {
156 db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " ADD " + KEY_UUID +
157 " TEXT;");
158 updateColumns(db);
159 }
160 if (oldVersion < 10)
161 {
162 db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " ADD " + KEY_EXCLUDED_SUBNETS +
163 " TEXT;");
164 }
165 if (oldVersion < 11)
166 {
167 db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " ADD " + KEY_INCLUDED_SUBNETS +
168 " TEXT;");
169 }
170 }
171
172 private void updateColumns(SQLiteDatabase db)
173 {
174 db.beginTransaction();
175 try
176 {
177 db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " RENAME TO tmp_" + TABLE_VPNPROFILE + ";");
178 db.execSQL(DATABASE_CREATE);
179 StringBuilder insert = new StringBuilder("INSERT INTO " + TABLE_VPNPROFILE + " SELECT ");
180 SQLiteQueryBuilder.appendColumns(insert, ALL_COLUMNS);
181 db.execSQL(insert.append(" FROM tmp_" + TABLE_VPNPROFILE + ";").toString());
182 db.execSQL("DROP TABLE tmp_" + TABLE_VPNPROFILE + ";");
183 db.setTransactionSuccessful();
184 }
185 finally
186 {
187 db.endTransaction();
188 }
189 }
190 }
191
192 /**
193 * Construct a new VPN profile data source. The context is used to
194 * open/create the database.
195 * @param context context used to access the database
196 */
197 public VpnProfileDataSource(Context context)
198 {
199 this.mContext = context;
200 }
201
202 /**
203 * Open the VPN profile data source. The database is automatically created
204 * if it does not yet exist. If that fails an exception is thrown.
205 * @return itself (allows to chain initialization calls)
206 * @throws SQLException if the database could not be opened or created
207 */
208 public VpnProfileDataSource open() throws SQLException
209 {
210 if (mDbHelper == null)
211 {
212 mDbHelper = new DatabaseHelper(mContext);
213 mDatabase = mDbHelper.getWritableDatabase();
214 }
215 return this;
216 }
217
218 /**
219 * Close the data source.
220 */
221 public void close()
222 {
223 if (mDbHelper != null)
224 {
225 mDbHelper.close();
226 mDbHelper = null;
227 }
228 }
229
230 /**
231 * Insert the given VPN profile into the database. On success the Id of
232 * the object is updated and the object returned.
233 *
234 * @param profile the profile to add
235 * @return the added VPN profile or null, if failed
236 */
237 public VpnProfile insertProfile(VpnProfile profile)
238 {
239 ContentValues values = ContentValuesFromVpnProfile(profile);
240 long insertId = mDatabase.insert(TABLE_VPNPROFILE, null, values);
241 if (insertId == -1)
242 {
243 return null;
244 }
245 profile.setId(insertId);
246 return profile;
247 }
248
249 /**
250 * Updates the given VPN profile in the database.
251 * @param profile the profile to update
252 * @return true if update succeeded, false otherwise
253 */
254 public boolean updateVpnProfile(VpnProfile profile)
255 {
256 long id = profile.getId();
257 ContentValues values = ContentValuesFromVpnProfile(profile);
258 return mDatabase.update(TABLE_VPNPROFILE, values, KEY_ID + " = " + id, null) > 0;
259 }
260
261 /**
262 * Delete the given VPN profile from the database.
263 * @param profile the profile to delete
264 * @return true if deleted, false otherwise
265 */
266 public boolean deleteVpnProfile(VpnProfile profile)
267 {
268 long id = profile.getId();
269 return mDatabase.delete(TABLE_VPNPROFILE, KEY_ID + " = " + id, null) > 0;
270 }
271
272 /**
273 * Get a single VPN profile from the database.
274 * @param id the ID of the VPN profile
275 * @return the profile or null, if not found
276 */
277 public VpnProfile getVpnProfile(long id)
278 {
279 VpnProfile profile = null;
280 Cursor cursor = mDatabase.query(TABLE_VPNPROFILE, ALL_COLUMNS,
281 KEY_ID + "=" + id, null, null, null, null);
282 if (cursor.moveToFirst())
283 {
284 profile = VpnProfileFromCursor(cursor);
285 }
286 cursor.close();
287 return profile;
288 }
289
290 /**
291 * Get a single VPN profile from the database by its UUID.
292 * @param uuid the UUID of the VPN profile
293 * @return the profile or null, if not found
294 */
295 public VpnProfile getVpnProfile(UUID uuid)
296 {
297 VpnProfile profile = null;
298 Cursor cursor = mDatabase.query(TABLE_VPNPROFILE, ALL_COLUMNS,
299 KEY_UUID + "='" + uuid.toString() + "'", null, null, null, null);
300 if (cursor.moveToFirst())
301 {
302 profile = VpnProfileFromCursor(cursor);
303 }
304 cursor.close();
305 return profile;
306 }
307
308 /**
309 * Get a list of all VPN profiles stored in the database.
310 * @return list of VPN profiles
311 */
312 public List<VpnProfile> getAllVpnProfiles()
313 {
314 List<VpnProfile> vpnProfiles = new ArrayList<VpnProfile>();
315
316 Cursor cursor = mDatabase.query(TABLE_VPNPROFILE, ALL_COLUMNS, null, null, null, null, null);
317 cursor.moveToFirst();
318 while (!cursor.isAfterLast())
319 {
320 VpnProfile vpnProfile = VpnProfileFromCursor(cursor);
321 vpnProfiles.add(vpnProfile);
322 cursor.moveToNext();
323 }
324 cursor.close();
325 return vpnProfiles;
326 }
327
328 private VpnProfile VpnProfileFromCursor(Cursor cursor)
329 {
330 VpnProfile profile = new VpnProfile();
331 profile.setId(cursor.getLong(cursor.getColumnIndex(KEY_ID)));
332 profile.setUUID(getUUID(cursor, cursor.getColumnIndex(KEY_UUID)));
333 profile.setName(cursor.getString(cursor.getColumnIndex(KEY_NAME)));
334 profile.setGateway(cursor.getString(cursor.getColumnIndex(KEY_GATEWAY)));
335 profile.setVpnType(VpnType.fromIdentifier(cursor.getString(cursor.getColumnIndex(KEY_VPN_TYPE))));
336 profile.setUsername(cursor.getString(cursor.getColumnIndex(KEY_USERNAME)));
337 profile.setPassword(cursor.getString(cursor.getColumnIndex(KEY_PASSWORD)));
338 profile.setCertificateAlias(cursor.getString(cursor.getColumnIndex(KEY_CERTIFICATE)));
339 profile.setUserCertificateAlias(cursor.getString(cursor.getColumnIndex(KEY_USER_CERTIFICATE)));
340 profile.setMTU(getInt(cursor, cursor.getColumnIndex(KEY_MTU)));
341 profile.setPort(getInt(cursor, cursor.getColumnIndex(KEY_PORT)));
342 profile.setSplitTunneling(getInt(cursor, cursor.getColumnIndex(KEY_SPLIT_TUNNELING)));
343 profile.setLocalId(cursor.getString(cursor.getColumnIndex(KEY_LOCAL_ID)));
344 profile.setRemoteId(cursor.getString(cursor.getColumnIndex(KEY_REMOTE_ID)));
345 profile.setExcludedSubnets(cursor.getString(cursor.getColumnIndex(KEY_EXCLUDED_SUBNETS)));
346 profile.setIncludedSubnets(cursor.getString(cursor.getColumnIndex(KEY_INCLUDED_SUBNETS)));
347 return profile;
348 }
349
350 private ContentValues ContentValuesFromVpnProfile(VpnProfile profile)
351 {
352 ContentValues values = new ContentValues();
353 values.put(KEY_UUID, profile.getUUID() != null ? profile.getUUID().toString() : null);
354 values.put(KEY_NAME, profile.getName());
355 values.put(KEY_GATEWAY, profile.getGateway());
356 values.put(KEY_VPN_TYPE, profile.getVpnType().getIdentifier());
357 values.put(KEY_USERNAME, profile.getUsername());
358 values.put(KEY_PASSWORD, profile.getPassword());
359 values.put(KEY_CERTIFICATE, profile.getCertificateAlias());
360 values.put(KEY_USER_CERTIFICATE, profile.getUserCertificateAlias());
361 values.put(KEY_MTU, profile.getMTU());
362 values.put(KEY_PORT, profile.getPort());
363 values.put(KEY_SPLIT_TUNNELING, profile.getSplitTunneling());
364 values.put(KEY_LOCAL_ID, profile.getLocalId());
365 values.put(KEY_REMOTE_ID, profile.getRemoteId());
366 values.put(KEY_EXCLUDED_SUBNETS, profile.getExcludedSubnets());
367 values.put(KEY_INCLUDED_SUBNETS, profile.getIncludedSubnets());
368 return values;
369 }
370
371 private Integer getInt(Cursor cursor, int columnIndex)
372 {
373 return cursor.isNull(columnIndex) ? null : cursor.getInt(columnIndex);
374 }
375
376 private UUID getUUID(Cursor cursor, int columnIndex)
377 {
378 try
379 {
380 return cursor.isNull(columnIndex) ? null : UUID.fromString(cursor.getString(columnIndex));
381 }
382 catch (Exception e)
383 {
384 return null;
385 }
386 }
387 }