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