]> git.ipfire.org Git - thirdparty/strongswan.git/blame - src/frontends/android/app/src/main/java/org/strongswan/android/data/VpnProfileDataSource.java
android: UUID is now mandatory
[thirdparty/strongswan.git] / src / frontends / android / app / src / main / java / org / strongswan / android / data / VpnProfileDataSource.java
CommitLineData
d799cbf6 1/*
93489acc 2 * Copyright (C) 2012-2018 Tobias Brunner
d799cbf6
TB
3 * Copyright (C) 2012 Giuliano Grassi
4 * Copyright (C) 2012 Ralf Sager
89149dbb 5 * HSR Hochschule fuer Technik Rapperswil
d799cbf6
TB
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
18package org.strongswan.android.data;
19
d799cbf6
TB
20import android.content.ContentValues;
21import android.content.Context;
22import android.database.Cursor;
23import android.database.SQLException;
24import android.database.sqlite.SQLiteDatabase;
25import android.database.sqlite.SQLiteOpenHelper;
3f9e90f6 26import android.database.sqlite.SQLiteQueryBuilder;
d799cbf6
TB
27import android.util.Log;
28
13ead876
TB
29import java.util.ArrayList;
30import java.util.List;
31import java.util.UUID;
32
d799cbf6
TB
33public class VpnProfileDataSource
34{
35 private static final String TAG = VpnProfileDataSource.class.getSimpleName();
36 public static final String KEY_ID = "_id";
c4ab9af7 37 public static final String KEY_UUID = "_uuid";
d799cbf6
TB
38 public static final String KEY_NAME = "name";
39 public static final String KEY_GATEWAY = "gateway";
48f51d94 40 public static final String KEY_VPN_TYPE = "vpn_type";
d799cbf6
TB
41 public static final String KEY_USERNAME = "username";
42 public static final String KEY_PASSWORD = "password";
43 public static final String KEY_CERTIFICATE = "certificate";
e09f4120 44 public static final String KEY_USER_CERTIFICATE = "user_certificate";
7e2a6c4a 45 public static final String KEY_MTU = "mtu";
5b11855f 46 public static final String KEY_PORT = "port";
f3d8da76 47 public static final String KEY_SPLIT_TUNNELING = "split_tunneling";
89149dbb
TB
48 public static final String KEY_LOCAL_ID = "local_id";
49 public static final String KEY_REMOTE_ID = "remote_id";
13ead876 50 public static final String KEY_EXCLUDED_SUBNETS = "excluded_subnets";
a9875259 51 public static final String KEY_INCLUDED_SUBNETS = "included_subnets";
43b33f07
TB
52 public static final String KEY_SELECTED_APPS = "selected_apps";
53 public static final String KEY_SELECTED_APPS_LIST = "selected_apps_list";
a2830231 54 public static final String KEY_NAT_KEEPALIVE = "nat_keepalive";
0204374e 55 public static final String KEY_FLAGS = "flags";
24c22a3f
TB
56 public static final String KEY_IKE_PROPOSAL = "ike_proposal";
57 public static final String KEY_ESP_PROPOSAL = "esp_proposal";
d799cbf6
TB
58
59 private DatabaseHelper mDbHelper;
60 private SQLiteDatabase mDatabase;
61 private final Context mContext;
62
63 private static final String DATABASE_NAME = "strongswan.db";
64 private static final String TABLE_VPNPROFILE = "vpnprofile";
65
93489acc 66 private static final int DATABASE_VERSION = 16;
d799cbf6 67
ccb6e9f1
TB
68 public static final DbColumn[] COLUMNS = new DbColumn[] {
69 new DbColumn(KEY_ID, "INTEGER PRIMARY KEY AUTOINCREMENT", 1),
70 new DbColumn(KEY_UUID, "TEXT UNIQUE", 9),
71 new DbColumn(KEY_NAME, "TEXT NOT NULL", 1),
72 new DbColumn(KEY_GATEWAY, "TEXT NOT NULL", 1),
73 new DbColumn(KEY_VPN_TYPE, "TEXT NOT NULL", 3),
74 new DbColumn(KEY_USERNAME, "TEXT", 1),
75 new DbColumn(KEY_PASSWORD, "TEXT", 1),
76 new DbColumn(KEY_CERTIFICATE, "TEXT", 1),
77 new DbColumn(KEY_USER_CERTIFICATE, "TEXT", 2),
78 new DbColumn(KEY_MTU, "INTEGER", 5),
79 new DbColumn(KEY_PORT, "INTEGER", 5),
80 new DbColumn(KEY_SPLIT_TUNNELING, "INTEGER", 7),
81 new DbColumn(KEY_LOCAL_ID, "TEXT", 8),
82 new DbColumn(KEY_REMOTE_ID, "TEXT", 8),
83 new DbColumn(KEY_EXCLUDED_SUBNETS, "TEXT", 10),
84 new DbColumn(KEY_INCLUDED_SUBNETS, "TEXT", 11),
85 new DbColumn(KEY_SELECTED_APPS, "INTEGER", 12),
86 new DbColumn(KEY_SELECTED_APPS_LIST, "TEXT", 12),
87 new DbColumn(KEY_NAT_KEEPALIVE, "INTEGER", 13),
88 new DbColumn(KEY_FLAGS, "INTEGER", 14),
24c22a3f
TB
89 new DbColumn(KEY_IKE_PROPOSAL, "TEXT", 15),
90 new DbColumn(KEY_ESP_PROPOSAL, "TEXT", 15),
d799cbf6
TB
91 };
92
ccb6e9f1
TB
93 private static final String[] ALL_COLUMNS = getColumns(DATABASE_VERSION);
94
95 private static String getDatabaseCreate(int version)
96 {
97 boolean first = true;
98 StringBuilder create = new StringBuilder("CREATE TABLE ");
99 create.append(TABLE_VPNPROFILE);
100 create.append(" (");
101 for (DbColumn column : COLUMNS)
102 {
103 if (column.Since <= version)
104 {
105 if (!first)
106 {
107 create.append(",");
108 }
109 first = false;
110 create.append(column.Name);
111 create.append(" ");
112 create.append(column.Type);
113 }
114 }
115 create.append(");");
116 return create.toString();
117 }
118
119 private static String[] getColumns(int version)
120 {
121 ArrayList<String> columns = new ArrayList<>();
122 for (DbColumn column : COLUMNS)
123 {
124 if (column.Since <= version)
125 {
126 columns.add(column.Name);
127 }
128 }
129 return columns.toArray(new String[0]);
130 }
131
d799cbf6
TB
132 private static class DatabaseHelper extends SQLiteOpenHelper
133 {
134 public DatabaseHelper(Context context)
135 {
136 super(context, DATABASE_NAME, null, DATABASE_VERSION);
137 }
138
139 @Override
140 public void onCreate(SQLiteDatabase database)
141 {
ccb6e9f1 142 database.execSQL(getDatabaseCreate(DATABASE_VERSION));
d799cbf6
TB
143 }
144
145 @Override
146 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
147 {
148 Log.w(TAG, "Upgrading database from version " + oldVersion +
e09f4120
TB
149 " to " + newVersion);
150 if (oldVersion < 2)
151 {
152 db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " ADD " + KEY_USER_CERTIFICATE +
153 " TEXT;");
154 }
48f51d94
TB
155 if (oldVersion < 3)
156 {
157 db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " ADD " + KEY_VPN_TYPE +
158 " TEXT DEFAULT '';");
159 }
3f9e90f6
TB
160 if (oldVersion < 4)
161 { /* remove NOT NULL constraint from username column */
ccb6e9f1 162 updateColumns(db, 4);
3f9e90f6 163 }
7e2a6c4a
TB
164 if (oldVersion < 5)
165 {
166 db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " ADD " + KEY_MTU +
167 " INTEGER;");
168 }
5b11855f
TB
169 if (oldVersion < 6)
170 {
171 db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " ADD " + KEY_PORT +
172 " INTEGER;");
173 }
f3d8da76
TB
174 if (oldVersion < 7)
175 {
176 db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " ADD " + KEY_SPLIT_TUNNELING +
177 " INTEGER;");
178 }
89149dbb
TB
179 if (oldVersion < 8)
180 {
181 db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " ADD " + KEY_LOCAL_ID +
182 " TEXT;");
183 db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " ADD " + KEY_REMOTE_ID +
184 " TEXT;");
185 }
c4ab9af7
TB
186 if (oldVersion < 9)
187 {
188 db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " ADD " + KEY_UUID +
189 " TEXT;");
ccb6e9f1 190 updateColumns(db, 9);
c4ab9af7 191 }
13ead876
TB
192 if (oldVersion < 10)
193 {
194 db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " ADD " + KEY_EXCLUDED_SUBNETS +
195 " TEXT;");
196 }
a9875259
TB
197 if (oldVersion < 11)
198 {
199 db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " ADD " + KEY_INCLUDED_SUBNETS +
200 " TEXT;");
201 }
43b33f07
TB
202 if (oldVersion < 12)
203 {
204 db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " ADD " + KEY_SELECTED_APPS +
205 " INTEGER;");
206 db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " ADD " + KEY_SELECTED_APPS_LIST +
207 " TEXT;");
208 }
a2830231
TB
209 if (oldVersion < 13)
210 {
211 db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " ADD " + KEY_NAT_KEEPALIVE +
212 " INTEGER;");
213 }
0204374e
TB
214 if (oldVersion < 14)
215 {
216 db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " ADD " + KEY_FLAGS +
217 " INTEGER;");
218 }
24c22a3f
TB
219 if (oldVersion < 15)
220 {
221 db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " ADD " + KEY_IKE_PROPOSAL +
222 " TEXT;");
223 db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " ADD " + KEY_ESP_PROPOSAL +
224 " TEXT;");
225 }
93489acc
TB
226 if (oldVersion < 16)
227 { /* add a UUID to all entries that haven't one yet */
228 db.beginTransaction();
229 try
230 {
231 Cursor cursor = db.query(TABLE_VPNPROFILE, ALL_COLUMNS, KEY_UUID + " is NULL", null, null, null, null);
232 for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext())
233 {
234 ContentValues values = new ContentValues();
235 values.put(KEY_UUID, UUID.randomUUID().toString());
236 db.update(TABLE_VPNPROFILE, values, KEY_ID + " = " + cursor.getLong(cursor.getColumnIndex(KEY_ID)), null);
237 }
238 cursor.close();
239 db.setTransactionSuccessful();
240 }
241 finally
242 {
243 db.endTransaction();
244 }
245 }
3f9e90f6
TB
246 }
247
ccb6e9f1 248 private void updateColumns(SQLiteDatabase db, int version)
3f9e90f6
TB
249 {
250 db.beginTransaction();
251 try
252 {
253 db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " RENAME TO tmp_" + TABLE_VPNPROFILE + ";");
ccb6e9f1 254 db.execSQL(getDatabaseCreate(version));
3f9e90f6 255 StringBuilder insert = new StringBuilder("INSERT INTO " + TABLE_VPNPROFILE + " SELECT ");
ccb6e9f1 256 SQLiteQueryBuilder.appendColumns(insert, getColumns(version));
3f9e90f6
TB
257 db.execSQL(insert.append(" FROM tmp_" + TABLE_VPNPROFILE + ";").toString());
258 db.execSQL("DROP TABLE tmp_" + TABLE_VPNPROFILE + ";");
259 db.setTransactionSuccessful();
260 }
261 finally
262 {
263 db.endTransaction();
264 }
d799cbf6
TB
265 }
266 }
267
268 /**
269 * Construct a new VPN profile data source. The context is used to
270 * open/create the database.
271 * @param context context used to access the database
272 */
273 public VpnProfileDataSource(Context context)
274 {
275 this.mContext = context;
276 }
277
278 /**
279 * Open the VPN profile data source. The database is automatically created
280 * if it does not yet exist. If that fails an exception is thrown.
281 * @return itself (allows to chain initialization calls)
282 * @throws SQLException if the database could not be opened or created
283 */
284 public VpnProfileDataSource open() throws SQLException
285 {
286 if (mDbHelper == null)
287 {
288 mDbHelper = new DatabaseHelper(mContext);
289 mDatabase = mDbHelper.getWritableDatabase();
290 }
291 return this;
292 }
293
294 /**
295 * Close the data source.
296 */
297 public void close()
298 {
299 if (mDbHelper != null)
300 {
301 mDbHelper.close();
302 mDbHelper = null;
303 }
304 }
305
306 /**
307 * Insert the given VPN profile into the database. On success the Id of
308 * the object is updated and the object returned.
309 *
310 * @param profile the profile to add
311 * @return the added VPN profile or null, if failed
312 */
313 public VpnProfile insertProfile(VpnProfile profile)
314 {
315 ContentValues values = ContentValuesFromVpnProfile(profile);
316 long insertId = mDatabase.insert(TABLE_VPNPROFILE, null, values);
317 if (insertId == -1)
318 {
319 return null;
320 }
321 profile.setId(insertId);
322 return profile;
323 }
324
325 /**
326 * Updates the given VPN profile in the database.
327 * @param profile the profile to update
328 * @return true if update succeeded, false otherwise
329 */
330 public boolean updateVpnProfile(VpnProfile profile)
331 {
332 long id = profile.getId();
333 ContentValues values = ContentValuesFromVpnProfile(profile);
334 return mDatabase.update(TABLE_VPNPROFILE, values, KEY_ID + " = " + id, null) > 0;
335 }
336
337 /**
338 * Delete the given VPN profile from the database.
339 * @param profile the profile to delete
340 * @return true if deleted, false otherwise
341 */
342 public boolean deleteVpnProfile(VpnProfile profile)
343 {
344 long id = profile.getId();
345 return mDatabase.delete(TABLE_VPNPROFILE, KEY_ID + " = " + id, null) > 0;
346 }
347
348 /**
349 * Get a single VPN profile from the database.
350 * @param id the ID of the VPN profile
351 * @return the profile or null, if not found
352 */
353 public VpnProfile getVpnProfile(long id)
354 {
355 VpnProfile profile = null;
356 Cursor cursor = mDatabase.query(TABLE_VPNPROFILE, ALL_COLUMNS,
357 KEY_ID + "=" + id, null, null, null, null);
358 if (cursor.moveToFirst())
359 {
360 profile = VpnProfileFromCursor(cursor);
361 }
362 cursor.close();
363 return profile;
364 }
365
c4ab9af7
TB
366 /**
367 * Get a single VPN profile from the database by its UUID.
368 * @param uuid the UUID of the VPN profile
369 * @return the profile or null, if not found
370 */
371 public VpnProfile getVpnProfile(UUID uuid)
372 {
373 VpnProfile profile = null;
374 Cursor cursor = mDatabase.query(TABLE_VPNPROFILE, ALL_COLUMNS,
375 KEY_UUID + "='" + uuid.toString() + "'", null, null, null, null);
376 if (cursor.moveToFirst())
377 {
378 profile = VpnProfileFromCursor(cursor);
379 }
380 cursor.close();
381 return profile;
382 }
383
d799cbf6
TB
384 /**
385 * Get a list of all VPN profiles stored in the database.
386 * @return list of VPN profiles
387 */
388 public List<VpnProfile> getAllVpnProfiles()
389 {
390 List<VpnProfile> vpnProfiles = new ArrayList<VpnProfile>();
391
392 Cursor cursor = mDatabase.query(TABLE_VPNPROFILE, ALL_COLUMNS, null, null, null, null, null);
393 cursor.moveToFirst();
394 while (!cursor.isAfterLast())
395 {
396 VpnProfile vpnProfile = VpnProfileFromCursor(cursor);
397 vpnProfiles.add(vpnProfile);
398 cursor.moveToNext();
399 }
400 cursor.close();
401 return vpnProfiles;
402 }
403
404 private VpnProfile VpnProfileFromCursor(Cursor cursor)
405 {
406 VpnProfile profile = new VpnProfile();
407 profile.setId(cursor.getLong(cursor.getColumnIndex(KEY_ID)));
93489acc 408 profile.setUUID(UUID.fromString(cursor.getString(cursor.getColumnIndex(KEY_UUID))));
d799cbf6
TB
409 profile.setName(cursor.getString(cursor.getColumnIndex(KEY_NAME)));
410 profile.setGateway(cursor.getString(cursor.getColumnIndex(KEY_GATEWAY)));
48f51d94 411 profile.setVpnType(VpnType.fromIdentifier(cursor.getString(cursor.getColumnIndex(KEY_VPN_TYPE))));
d799cbf6
TB
412 profile.setUsername(cursor.getString(cursor.getColumnIndex(KEY_USERNAME)));
413 profile.setPassword(cursor.getString(cursor.getColumnIndex(KEY_PASSWORD)));
414 profile.setCertificateAlias(cursor.getString(cursor.getColumnIndex(KEY_CERTIFICATE)));
e09f4120 415 profile.setUserCertificateAlias(cursor.getString(cursor.getColumnIndex(KEY_USER_CERTIFICATE)));
7e2a6c4a 416 profile.setMTU(getInt(cursor, cursor.getColumnIndex(KEY_MTU)));
5b11855f 417 profile.setPort(getInt(cursor, cursor.getColumnIndex(KEY_PORT)));
f3d8da76 418 profile.setSplitTunneling(getInt(cursor, cursor.getColumnIndex(KEY_SPLIT_TUNNELING)));
89149dbb
TB
419 profile.setLocalId(cursor.getString(cursor.getColumnIndex(KEY_LOCAL_ID)));
420 profile.setRemoteId(cursor.getString(cursor.getColumnIndex(KEY_REMOTE_ID)));
13ead876 421 profile.setExcludedSubnets(cursor.getString(cursor.getColumnIndex(KEY_EXCLUDED_SUBNETS)));
a9875259 422 profile.setIncludedSubnets(cursor.getString(cursor.getColumnIndex(KEY_INCLUDED_SUBNETS)));
43b33f07
TB
423 profile.setSelectedAppsHandling(getInt(cursor, cursor.getColumnIndex(KEY_SELECTED_APPS)));
424 profile.setSelectedApps(cursor.getString(cursor.getColumnIndex(KEY_SELECTED_APPS_LIST)));
a2830231 425 profile.setNATKeepAlive(getInt(cursor, cursor.getColumnIndex(KEY_NAT_KEEPALIVE)));
0204374e 426 profile.setFlags(getInt(cursor, cursor.getColumnIndex(KEY_FLAGS)));
24c22a3f
TB
427 profile.setIkeProposal(cursor.getString(cursor.getColumnIndex(KEY_IKE_PROPOSAL)));
428 profile.setEspProposal(cursor.getString(cursor.getColumnIndex(KEY_ESP_PROPOSAL)));
d799cbf6
TB
429 return profile;
430 }
431
432 private ContentValues ContentValuesFromVpnProfile(VpnProfile profile)
433 {
434 ContentValues values = new ContentValues();
93489acc 435 values.put(KEY_UUID, profile.getUUID().toString());
d799cbf6
TB
436 values.put(KEY_NAME, profile.getName());
437 values.put(KEY_GATEWAY, profile.getGateway());
48f51d94 438 values.put(KEY_VPN_TYPE, profile.getVpnType().getIdentifier());
d799cbf6
TB
439 values.put(KEY_USERNAME, profile.getUsername());
440 values.put(KEY_PASSWORD, profile.getPassword());
441 values.put(KEY_CERTIFICATE, profile.getCertificateAlias());
e09f4120 442 values.put(KEY_USER_CERTIFICATE, profile.getUserCertificateAlias());
7e2a6c4a 443 values.put(KEY_MTU, profile.getMTU());
5b11855f 444 values.put(KEY_PORT, profile.getPort());
f3d8da76 445 values.put(KEY_SPLIT_TUNNELING, profile.getSplitTunneling());
89149dbb
TB
446 values.put(KEY_LOCAL_ID, profile.getLocalId());
447 values.put(KEY_REMOTE_ID, profile.getRemoteId());
13ead876 448 values.put(KEY_EXCLUDED_SUBNETS, profile.getExcludedSubnets());
a9875259 449 values.put(KEY_INCLUDED_SUBNETS, profile.getIncludedSubnets());
43b33f07
TB
450 values.put(KEY_SELECTED_APPS, profile.getSelectedAppsHandling().getValue());
451 values.put(KEY_SELECTED_APPS_LIST, profile.getSelectedApps());
a2830231 452 values.put(KEY_NAT_KEEPALIVE, profile.getNATKeepAlive());
0204374e 453 values.put(KEY_FLAGS, profile.getFlags());
24c22a3f
TB
454 values.put(KEY_IKE_PROPOSAL, profile.getIkeProposal());
455 values.put(KEY_ESP_PROPOSAL, profile.getEspProposal());
d799cbf6
TB
456 return values;
457 }
7e2a6c4a
TB
458
459 private Integer getInt(Cursor cursor, int columnIndex)
460 {
461 return cursor.isNull(columnIndex) ? null : cursor.getInt(columnIndex);
462 }
c4ab9af7 463
ccb6e9f1
TB
464 private static class DbColumn
465 {
466 public final String Name;
467 public final String Type;
468 public final Integer Since;
469
470 public DbColumn(String name, String type, Integer since)
471 {
472 Name = name;
473 Type = type;
474 Since = since;
475 }
476 }
d799cbf6 477}