android: Add property for excluded 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
52 private DatabaseHelper mDbHelper;
53 private SQLiteDatabase mDatabase;
54 private final Context mContext;
55
56 private static final String DATABASE_NAME = "strongswan.db";
57 private static final String TABLE_VPNPROFILE = "vpnprofile";
58
59 private static final int DATABASE_VERSION = 10;
60
61 public static final String DATABASE_CREATE =
62 "CREATE TABLE " + TABLE_VPNPROFILE + " (" +
63 KEY_ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
64 KEY_UUID + " TEXT UNIQUE," +
65 KEY_NAME + " TEXT NOT NULL," +
66 KEY_GATEWAY + " TEXT NOT NULL," +
67 KEY_VPN_TYPE + " TEXT NOT NULL," +
68 KEY_USERNAME + " TEXT," +
69 KEY_PASSWORD + " TEXT," +
70 KEY_CERTIFICATE + " TEXT," +
71 KEY_USER_CERTIFICATE + " TEXT," +
72 KEY_MTU + " INTEGER," +
73 KEY_PORT + " INTEGER," +
74 KEY_SPLIT_TUNNELING + " INTEGER," +
75 KEY_LOCAL_ID + " TEXT," +
76 KEY_REMOTE_ID + " TEXT," +
77 KEY_EXCLUDED_SUBNETS + " TEXT" +
78 ");";
79 private static final String[] ALL_COLUMNS = new String[] {
80 KEY_ID,
81 KEY_UUID,
82 KEY_NAME,
83 KEY_GATEWAY,
84 KEY_VPN_TYPE,
85 KEY_USERNAME,
86 KEY_PASSWORD,
87 KEY_CERTIFICATE,
88 KEY_USER_CERTIFICATE,
89 KEY_MTU,
90 KEY_PORT,
91 KEY_SPLIT_TUNNELING,
92 KEY_LOCAL_ID,
93 KEY_REMOTE_ID,
94 KEY_EXCLUDED_SUBNETS,
95 };
96
97 private static class DatabaseHelper extends SQLiteOpenHelper
98 {
99 public DatabaseHelper(Context context)
100 {
101 super(context, DATABASE_NAME, null, DATABASE_VERSION);
102 }
103
104 @Override
105 public void onCreate(SQLiteDatabase database)
106 {
107 database.execSQL(DATABASE_CREATE);
108 }
109
110 @Override
111 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
112 {
113 Log.w(TAG, "Upgrading database from version " + oldVersion +
114 " to " + newVersion);
115 if (oldVersion < 2)
116 {
117 db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " ADD " + KEY_USER_CERTIFICATE +
118 " TEXT;");
119 }
120 if (oldVersion < 3)
121 {
122 db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " ADD " + KEY_VPN_TYPE +
123 " TEXT DEFAULT '';");
124 }
125 if (oldVersion < 4)
126 { /* remove NOT NULL constraint from username column */
127 updateColumns(db);
128 }
129 if (oldVersion < 5)
130 {
131 db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " ADD " + KEY_MTU +
132 " INTEGER;");
133 }
134 if (oldVersion < 6)
135 {
136 db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " ADD " + KEY_PORT +
137 " INTEGER;");
138 }
139 if (oldVersion < 7)
140 {
141 db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " ADD " + KEY_SPLIT_TUNNELING +
142 " INTEGER;");
143 }
144 if (oldVersion < 8)
145 {
146 db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " ADD " + KEY_LOCAL_ID +
147 " TEXT;");
148 db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " ADD " + KEY_REMOTE_ID +
149 " TEXT;");
150 }
151 if (oldVersion < 9)
152 {
153 db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " ADD " + KEY_UUID +
154 " TEXT;");
155 updateColumns(db);
156 }
157 if (oldVersion < 10)
158 {
159 db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " ADD " + KEY_EXCLUDED_SUBNETS +
160 " TEXT;");
161 }
162 }
163
164 private void updateColumns(SQLiteDatabase db)
165 {
166 db.beginTransaction();
167 try
168 {
169 db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " RENAME TO tmp_" + TABLE_VPNPROFILE + ";");
170 db.execSQL(DATABASE_CREATE);
171 StringBuilder insert = new StringBuilder("INSERT INTO " + TABLE_VPNPROFILE + " SELECT ");
172 SQLiteQueryBuilder.appendColumns(insert, ALL_COLUMNS);
173 db.execSQL(insert.append(" FROM tmp_" + TABLE_VPNPROFILE + ";").toString());
174 db.execSQL("DROP TABLE tmp_" + TABLE_VPNPROFILE + ";");
175 db.setTransactionSuccessful();
176 }
177 finally
178 {
179 db.endTransaction();
180 }
181 }
182 }
183
184 /**
185 * Construct a new VPN profile data source. The context is used to
186 * open/create the database.
187 * @param context context used to access the database
188 */
189 public VpnProfileDataSource(Context context)
190 {
191 this.mContext = context;
192 }
193
194 /**
195 * Open the VPN profile data source. The database is automatically created
196 * if it does not yet exist. If that fails an exception is thrown.
197 * @return itself (allows to chain initialization calls)
198 * @throws SQLException if the database could not be opened or created
199 */
200 public VpnProfileDataSource open() throws SQLException
201 {
202 if (mDbHelper == null)
203 {
204 mDbHelper = new DatabaseHelper(mContext);
205 mDatabase = mDbHelper.getWritableDatabase();
206 }
207 return this;
208 }
209
210 /**
211 * Close the data source.
212 */
213 public void close()
214 {
215 if (mDbHelper != null)
216 {
217 mDbHelper.close();
218 mDbHelper = null;
219 }
220 }
221
222 /**
223 * Insert the given VPN profile into the database. On success the Id of
224 * the object is updated and the object returned.
225 *
226 * @param profile the profile to add
227 * @return the added VPN profile or null, if failed
228 */
229 public VpnProfile insertProfile(VpnProfile profile)
230 {
231 ContentValues values = ContentValuesFromVpnProfile(profile);
232 long insertId = mDatabase.insert(TABLE_VPNPROFILE, null, values);
233 if (insertId == -1)
234 {
235 return null;
236 }
237 profile.setId(insertId);
238 return profile;
239 }
240
241 /**
242 * Updates the given VPN profile in the database.
243 * @param profile the profile to update
244 * @return true if update succeeded, false otherwise
245 */
246 public boolean updateVpnProfile(VpnProfile profile)
247 {
248 long id = profile.getId();
249 ContentValues values = ContentValuesFromVpnProfile(profile);
250 return mDatabase.update(TABLE_VPNPROFILE, values, KEY_ID + " = " + id, null) > 0;
251 }
252
253 /**
254 * Delete the given VPN profile from the database.
255 * @param profile the profile to delete
256 * @return true if deleted, false otherwise
257 */
258 public boolean deleteVpnProfile(VpnProfile profile)
259 {
260 long id = profile.getId();
261 return mDatabase.delete(TABLE_VPNPROFILE, KEY_ID + " = " + id, null) > 0;
262 }
263
264 /**
265 * Get a single VPN profile from the database.
266 * @param id the ID of the VPN profile
267 * @return the profile or null, if not found
268 */
269 public VpnProfile getVpnProfile(long id)
270 {
271 VpnProfile profile = null;
272 Cursor cursor = mDatabase.query(TABLE_VPNPROFILE, ALL_COLUMNS,
273 KEY_ID + "=" + id, null, null, null, null);
274 if (cursor.moveToFirst())
275 {
276 profile = VpnProfileFromCursor(cursor);
277 }
278 cursor.close();
279 return profile;
280 }
281
282 /**
283 * Get a single VPN profile from the database by its UUID.
284 * @param uuid the UUID of the VPN profile
285 * @return the profile or null, if not found
286 */
287 public VpnProfile getVpnProfile(UUID uuid)
288 {
289 VpnProfile profile = null;
290 Cursor cursor = mDatabase.query(TABLE_VPNPROFILE, ALL_COLUMNS,
291 KEY_UUID + "='" + uuid.toString() + "'", null, null, null, null);
292 if (cursor.moveToFirst())
293 {
294 profile = VpnProfileFromCursor(cursor);
295 }
296 cursor.close();
297 return profile;
298 }
299
300 /**
301 * Get a list of all VPN profiles stored in the database.
302 * @return list of VPN profiles
303 */
304 public List<VpnProfile> getAllVpnProfiles()
305 {
306 List<VpnProfile> vpnProfiles = new ArrayList<VpnProfile>();
307
308 Cursor cursor = mDatabase.query(TABLE_VPNPROFILE, ALL_COLUMNS, null, null, null, null, null);
309 cursor.moveToFirst();
310 while (!cursor.isAfterLast())
311 {
312 VpnProfile vpnProfile = VpnProfileFromCursor(cursor);
313 vpnProfiles.add(vpnProfile);
314 cursor.moveToNext();
315 }
316 cursor.close();
317 return vpnProfiles;
318 }
319
320 private VpnProfile VpnProfileFromCursor(Cursor cursor)
321 {
322 VpnProfile profile = new VpnProfile();
323 profile.setId(cursor.getLong(cursor.getColumnIndex(KEY_ID)));
324 profile.setUUID(getUUID(cursor, cursor.getColumnIndex(KEY_UUID)));
325 profile.setName(cursor.getString(cursor.getColumnIndex(KEY_NAME)));
326 profile.setGateway(cursor.getString(cursor.getColumnIndex(KEY_GATEWAY)));
327 profile.setVpnType(VpnType.fromIdentifier(cursor.getString(cursor.getColumnIndex(KEY_VPN_TYPE))));
328 profile.setUsername(cursor.getString(cursor.getColumnIndex(KEY_USERNAME)));
329 profile.setPassword(cursor.getString(cursor.getColumnIndex(KEY_PASSWORD)));
330 profile.setCertificateAlias(cursor.getString(cursor.getColumnIndex(KEY_CERTIFICATE)));
331 profile.setUserCertificateAlias(cursor.getString(cursor.getColumnIndex(KEY_USER_CERTIFICATE)));
332 profile.setMTU(getInt(cursor, cursor.getColumnIndex(KEY_MTU)));
333 profile.setPort(getInt(cursor, cursor.getColumnIndex(KEY_PORT)));
334 profile.setSplitTunneling(getInt(cursor, cursor.getColumnIndex(KEY_SPLIT_TUNNELING)));
335 profile.setLocalId(cursor.getString(cursor.getColumnIndex(KEY_LOCAL_ID)));
336 profile.setRemoteId(cursor.getString(cursor.getColumnIndex(KEY_REMOTE_ID)));
337 profile.setExcludedSubnets(cursor.getString(cursor.getColumnIndex(KEY_EXCLUDED_SUBNETS)));
338 return profile;
339 }
340
341 private ContentValues ContentValuesFromVpnProfile(VpnProfile profile)
342 {
343 ContentValues values = new ContentValues();
344 values.put(KEY_UUID, profile.getUUID() != null ? profile.getUUID().toString() : null);
345 values.put(KEY_NAME, profile.getName());
346 values.put(KEY_GATEWAY, profile.getGateway());
347 values.put(KEY_VPN_TYPE, profile.getVpnType().getIdentifier());
348 values.put(KEY_USERNAME, profile.getUsername());
349 values.put(KEY_PASSWORD, profile.getPassword());
350 values.put(KEY_CERTIFICATE, profile.getCertificateAlias());
351 values.put(KEY_USER_CERTIFICATE, profile.getUserCertificateAlias());
352 values.put(KEY_MTU, profile.getMTU());
353 values.put(KEY_PORT, profile.getPort());
354 values.put(KEY_SPLIT_TUNNELING, profile.getSplitTunneling());
355 values.put(KEY_LOCAL_ID, profile.getLocalId());
356 values.put(KEY_REMOTE_ID, profile.getRemoteId());
357 values.put(KEY_EXCLUDED_SUBNETS, profile.getExcludedSubnets());
358 return values;
359 }
360
361 private Integer getInt(Cursor cursor, int columnIndex)
362 {
363 return cursor.isNull(columnIndex) ? null : cursor.getInt(columnIndex);
364 }
365
366 private UUID getUUID(Cursor cursor, int columnIndex)
367 {
368 try
369 {
370 return cursor.isNull(columnIndex) ? null : UUID.fromString(cursor.getString(columnIndex));
371 }
372 catch (Exception e)
373 {
374 return null;
375 }
376 }
377 }