From 7c8773dea51f36c999eea9c7d3a1a34d238abeae Mon Sep 17 00:00:00 2001 From: Markus Pfeiffer Date: Tue, 21 Nov 2023 15:37:21 +0100 Subject: [PATCH] android: Add interface for VPN data source Change VPN profile source to an interface. Preparation to allow managed configurations as a second source. --- .../android/data/VpnProfileDataSource.java | 454 ++---------------- .../android/data/VpnProfileSource.java | 114 +++++ .../android/data/VpnProfileSqlDataSource.java | 433 +++++++++++++++++ .../android/logic/CharonVpnService.java | 3 +- .../android/ui/SettingsFragment.java | 16 +- .../android/ui/VpnProfileControlActivity.java | 12 +- .../android/ui/VpnProfileDetailActivity.java | 3 +- .../android/ui/VpnProfileImportActivity.java | 3 +- .../android/ui/VpnProfileListFragment.java | 34 +- .../strongswan/android/ui/VpnTileService.java | 3 +- 10 files changed, 631 insertions(+), 444 deletions(-) create mode 100644 src/frontends/android/app/src/main/java/org/strongswan/android/data/VpnProfileSource.java create mode 100644 src/frontends/android/app/src/main/java/org/strongswan/android/data/VpnProfileSqlDataSource.java diff --git a/src/frontends/android/app/src/main/java/org/strongswan/android/data/VpnProfileDataSource.java b/src/frontends/android/app/src/main/java/org/strongswan/android/data/VpnProfileDataSource.java index 5604f67a1a..07308956c7 100644 --- a/src/frontends/android/app/src/main/java/org/strongswan/android/data/VpnProfileDataSource.java +++ b/src/frontends/android/app/src/main/java/org/strongswan/android/data/VpnProfileDataSource.java @@ -1,4 +1,5 @@ /* + * Copyright (C) 2023 Relution GmbH * Copyright (C) 2012-2019 Tobias Brunner * Copyright (C) 2012 Giuliano Grassi * Copyright (C) 2012 Ralf Sager @@ -18,298 +19,50 @@ package org.strongswan.android.data; -import android.content.ContentValues; -import android.content.Context; -import android.database.Cursor; import android.database.SQLException; -import android.database.sqlite.SQLiteDatabase; -import android.database.sqlite.SQLiteOpenHelper; -import android.database.sqlite.SQLiteQueryBuilder; -import android.util.Log; -import java.util.ArrayList; import java.util.List; import java.util.UUID; -public class VpnProfileDataSource +public interface VpnProfileDataSource { - private static final String TAG = VpnProfileDataSource.class.getSimpleName(); - public static final String KEY_ID = "_id"; - public static final String KEY_UUID = "_uuid"; - public static final String KEY_NAME = "name"; - public static final String KEY_GATEWAY = "gateway"; - public static final String KEY_VPN_TYPE = "vpn_type"; - public static final String KEY_USERNAME = "username"; - public static final String KEY_PASSWORD = "password"; - public static final String KEY_CERTIFICATE = "certificate"; - public static final String KEY_USER_CERTIFICATE = "user_certificate"; - public static final String KEY_MTU = "mtu"; - public static final String KEY_PORT = "port"; - public static final String KEY_SPLIT_TUNNELING = "split_tunneling"; - public static final String KEY_LOCAL_ID = "local_id"; - public static final String KEY_REMOTE_ID = "remote_id"; - public static final String KEY_EXCLUDED_SUBNETS = "excluded_subnets"; - public static final String KEY_INCLUDED_SUBNETS = "included_subnets"; - public static final String KEY_SELECTED_APPS = "selected_apps"; - public static final String KEY_SELECTED_APPS_LIST = "selected_apps_list"; - public static final String KEY_NAT_KEEPALIVE = "nat_keepalive"; - public static final String KEY_FLAGS = "flags"; - public static final String KEY_IKE_PROPOSAL = "ike_proposal"; - public static final String KEY_ESP_PROPOSAL = "esp_proposal"; - public static final String KEY_DNS_SERVERS = "dns_servers"; - - private DatabaseHelper mDbHelper; - private SQLiteDatabase mDatabase; - private final Context mContext; - - private static final String DATABASE_NAME = "strongswan.db"; - private static final String TABLE_VPNPROFILE = "vpnprofile"; - - private static final int DATABASE_VERSION = 17; - - public static final DbColumn[] COLUMNS = new DbColumn[] { - new DbColumn(KEY_ID, "INTEGER PRIMARY KEY AUTOINCREMENT", 1), - new DbColumn(KEY_UUID, "TEXT UNIQUE", 9), - new DbColumn(KEY_NAME, "TEXT NOT NULL", 1), - new DbColumn(KEY_GATEWAY, "TEXT NOT NULL", 1), - new DbColumn(KEY_VPN_TYPE, "TEXT NOT NULL", 3), - new DbColumn(KEY_USERNAME, "TEXT", 1), - new DbColumn(KEY_PASSWORD, "TEXT", 1), - new DbColumn(KEY_CERTIFICATE, "TEXT", 1), - new DbColumn(KEY_USER_CERTIFICATE, "TEXT", 2), - new DbColumn(KEY_MTU, "INTEGER", 5), - new DbColumn(KEY_PORT, "INTEGER", 5), - new DbColumn(KEY_SPLIT_TUNNELING, "INTEGER", 7), - new DbColumn(KEY_LOCAL_ID, "TEXT", 8), - new DbColumn(KEY_REMOTE_ID, "TEXT", 8), - new DbColumn(KEY_EXCLUDED_SUBNETS, "TEXT", 10), - new DbColumn(KEY_INCLUDED_SUBNETS, "TEXT", 11), - new DbColumn(KEY_SELECTED_APPS, "INTEGER", 12), - new DbColumn(KEY_SELECTED_APPS_LIST, "TEXT", 12), - new DbColumn(KEY_NAT_KEEPALIVE, "INTEGER", 13), - new DbColumn(KEY_FLAGS, "INTEGER", 14), - new DbColumn(KEY_IKE_PROPOSAL, "TEXT", 15), - new DbColumn(KEY_ESP_PROPOSAL, "TEXT", 15), - new DbColumn(KEY_DNS_SERVERS, "TEXT", 17), - }; - - private static final String[] ALL_COLUMNS = getColumns(DATABASE_VERSION); - - private static String getDatabaseCreate(int version) - { - boolean first = true; - StringBuilder create = new StringBuilder("CREATE TABLE "); - create.append(TABLE_VPNPROFILE); - create.append(" ("); - for (DbColumn column : COLUMNS) - { - if (column.Since <= version) - { - if (!first) - { - create.append(","); - } - first = false; - create.append(column.Name); - create.append(" "); - create.append(column.Type); - } - } - create.append(");"); - return create.toString(); - } - - private static String[] getColumns(int version) - { - ArrayList columns = new ArrayList<>(); - for (DbColumn column : COLUMNS) - { - if (column.Since <= version) - { - columns.add(column.Name); - } - } - return columns.toArray(new String[0]); - } - - private static class DatabaseHelper extends SQLiteOpenHelper - { - public DatabaseHelper(Context context) - { - super(context, DATABASE_NAME, null, DATABASE_VERSION); - } - - @Override - public void onCreate(SQLiteDatabase database) - { - database.execSQL(getDatabaseCreate(DATABASE_VERSION)); - } - - @Override - public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) - { - Log.w(TAG, "Upgrading database from version " + oldVersion + - " to " + newVersion); - if (oldVersion < 2) - { - db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " ADD " + KEY_USER_CERTIFICATE + - " TEXT;"); - } - if (oldVersion < 3) - { - db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " ADD " + KEY_VPN_TYPE + - " TEXT DEFAULT '';"); - } - if (oldVersion < 4) - { /* remove NOT NULL constraint from username column */ - updateColumns(db, 4); - } - if (oldVersion < 5) - { - db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " ADD " + KEY_MTU + - " INTEGER;"); - } - if (oldVersion < 6) - { - db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " ADD " + KEY_PORT + - " INTEGER;"); - } - if (oldVersion < 7) - { - db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " ADD " + KEY_SPLIT_TUNNELING + - " INTEGER;"); - } - if (oldVersion < 8) - { - db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " ADD " + KEY_LOCAL_ID + - " TEXT;"); - db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " ADD " + KEY_REMOTE_ID + - " TEXT;"); - } - if (oldVersion < 9) - { - db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " ADD " + KEY_UUID + - " TEXT;"); - updateColumns(db, 9); - } - if (oldVersion < 10) - { - db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " ADD " + KEY_EXCLUDED_SUBNETS + - " TEXT;"); - } - if (oldVersion < 11) - { - db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " ADD " + KEY_INCLUDED_SUBNETS + - " TEXT;"); - } - if (oldVersion < 12) - { - db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " ADD " + KEY_SELECTED_APPS + - " INTEGER;"); - db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " ADD " + KEY_SELECTED_APPS_LIST + - " TEXT;"); - } - if (oldVersion < 13) - { - db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " ADD " + KEY_NAT_KEEPALIVE + - " INTEGER;"); - } - if (oldVersion < 14) - { - db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " ADD " + KEY_FLAGS + - " INTEGER;"); - } - if (oldVersion < 15) - { - db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " ADD " + KEY_IKE_PROPOSAL + - " TEXT;"); - db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " ADD " + KEY_ESP_PROPOSAL + - " TEXT;"); - } - if (oldVersion < 16) - { /* add a UUID to all entries that haven't one yet */ - db.beginTransaction(); - try - { - Cursor cursor = db.query(TABLE_VPNPROFILE, getColumns(16), KEY_UUID + " is NULL", null, null, null, null); - for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) - { - ContentValues values = new ContentValues(); - values.put(KEY_UUID, UUID.randomUUID().toString()); - db.update(TABLE_VPNPROFILE, values, KEY_ID + " = " + cursor.getLong(cursor.getColumnIndexOrThrow(KEY_ID)), null); - } - cursor.close(); - db.setTransactionSuccessful(); - } - finally - { - db.endTransaction(); - } - } - if (oldVersion < 17) - { - db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " ADD " + KEY_DNS_SERVERS + - " TEXT;"); - } - } - - private void updateColumns(SQLiteDatabase db, int version) - { - db.beginTransaction(); - try - { - db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " RENAME TO tmp_" + TABLE_VPNPROFILE + ";"); - db.execSQL(getDatabaseCreate(version)); - StringBuilder insert = new StringBuilder("INSERT INTO " + TABLE_VPNPROFILE + " SELECT "); - SQLiteQueryBuilder.appendColumns(insert, getColumns(version)); - db.execSQL(insert.append(" FROM tmp_" + TABLE_VPNPROFILE + ";").toString()); - db.execSQL("DROP TABLE tmp_" + TABLE_VPNPROFILE + ";"); - db.setTransactionSuccessful(); - } - finally - { - db.endTransaction(); - } - } - } - - /** - * Construct a new VPN profile data source. The context is used to - * open/create the database. - * @param context context used to access the database - */ - public VpnProfileDataSource(Context context) - { - this.mContext = context; - } + String KEY_ID = "_id"; + String KEY_UUID = "_uuid"; + String KEY_NAME = "name"; + String KEY_GATEWAY = "gateway"; + String KEY_VPN_TYPE = "vpn_type"; + String KEY_USERNAME = "username"; + String KEY_PASSWORD = "password"; + String KEY_CERTIFICATE = "certificate"; + String KEY_USER_CERTIFICATE = "user_certificate"; + String KEY_MTU = "mtu"; + String KEY_PORT = "port"; + String KEY_SPLIT_TUNNELING = "split_tunneling"; + String KEY_LOCAL_ID = "local_id"; + String KEY_REMOTE_ID = "remote_id"; + String KEY_EXCLUDED_SUBNETS = "excluded_subnets"; + String KEY_INCLUDED_SUBNETS = "included_subnets"; + String KEY_SELECTED_APPS = "selected_apps"; + String KEY_SELECTED_APPS_LIST = "selected_apps_list"; + String KEY_NAT_KEEPALIVE = "nat_keepalive"; + String KEY_FLAGS = "flags"; + String KEY_IKE_PROPOSAL = "ike_proposal"; + String KEY_ESP_PROPOSAL = "esp_proposal"; + String KEY_DNS_SERVERS = "dns_servers"; /** * Open the VPN profile data source. The database is automatically created * if it does not yet exist. If that fails an exception is thrown. + * * @return itself (allows to chain initialization calls) * @throws SQLException if the database could not be opened or created */ - public VpnProfileDataSource open() throws SQLException - { - if (mDbHelper == null) - { - mDbHelper = new DatabaseHelper(mContext); - mDatabase = mDbHelper.getWritableDatabase(); - } - return this; - } + VpnProfileDataSource open() throws SQLException; /** * Close the data source. */ - public void close() - { - if (mDbHelper != null) - { - mDbHelper.close(); - mDbHelper = null; - } - } + void close(); /** * Insert the given VPN profile into the database. On success the Id of @@ -318,83 +71,47 @@ public class VpnProfileDataSource * @param profile the profile to add * @return the added VPN profile or null, if failed */ - public VpnProfile insertProfile(VpnProfile profile) - { - ContentValues values = ContentValuesFromVpnProfile(profile); - long insertId = mDatabase.insert(TABLE_VPNPROFILE, null, values); - if (insertId == -1) - { - return null; - } - profile.setId(insertId); - return profile; - } + VpnProfile insertProfile(VpnProfile profile); /** * Updates the given VPN profile in the database. + * * @param profile the profile to update * @return true if update succeeded, false otherwise */ - public boolean updateVpnProfile(VpnProfile profile) - { - long id = profile.getId(); - ContentValues values = ContentValuesFromVpnProfile(profile); - return mDatabase.update(TABLE_VPNPROFILE, values, KEY_ID + " = " + id, null) > 0; - } + boolean updateVpnProfile(VpnProfile profile); /** * Delete the given VPN profile from the database. + * * @param profile the profile to delete * @return true if deleted, false otherwise */ - public boolean deleteVpnProfile(VpnProfile profile) - { - long id = profile.getId(); - return mDatabase.delete(TABLE_VPNPROFILE, KEY_ID + " = " + id, null) > 0; - } + boolean deleteVpnProfile(VpnProfile profile); /** * Get a single VPN profile from the database. + * * @param id the ID of the VPN profile * @return the profile or null, if not found */ - public VpnProfile getVpnProfile(long id) - { - VpnProfile profile = null; - Cursor cursor = mDatabase.query(TABLE_VPNPROFILE, ALL_COLUMNS, - KEY_ID + "=" + id, null, null, null, null); - if (cursor.moveToFirst()) - { - profile = VpnProfileFromCursor(cursor); - } - cursor.close(); - return profile; - } + VpnProfile getVpnProfile(long id); /** * Get a single VPN profile from the database by its UUID. + * * @param uuid the UUID of the VPN profile * @return the profile or null, if not found */ - public VpnProfile getVpnProfile(UUID uuid) - { - VpnProfile profile = null; - Cursor cursor = mDatabase.query(TABLE_VPNPROFILE, ALL_COLUMNS, - KEY_UUID + "='" + uuid.toString() + "'", null, null, null, null); - if (cursor.moveToFirst()) - { - profile = VpnProfileFromCursor(cursor); - } - cursor.close(); - return profile; - } + VpnProfile getVpnProfile(UUID uuid); /** * Get a single VPN profile from the database by its UUID as String. + * * @param uuid the UUID of the VPN profile as String * @return the profile or null, if not found */ - public VpnProfile getVpnProfile(String uuid) + default VpnProfile getVpnProfile(String uuid) { try { @@ -413,97 +130,8 @@ public class VpnProfileDataSource /** * Get a list of all VPN profiles stored in the database. + * * @return list of VPN profiles */ - public List getAllVpnProfiles() - { - List vpnProfiles = new ArrayList(); - - Cursor cursor = mDatabase.query(TABLE_VPNPROFILE, ALL_COLUMNS, null, null, null, null, null); - cursor.moveToFirst(); - while (!cursor.isAfterLast()) - { - VpnProfile vpnProfile = VpnProfileFromCursor(cursor); - vpnProfiles.add(vpnProfile); - cursor.moveToNext(); - } - cursor.close(); - return vpnProfiles; - } - - private VpnProfile VpnProfileFromCursor(Cursor cursor) - { - VpnProfile profile = new VpnProfile(); - profile.setId(cursor.getLong(cursor.getColumnIndexOrThrow(KEY_ID))); - profile.setUUID(UUID.fromString(cursor.getString(cursor.getColumnIndexOrThrow(KEY_UUID)))); - profile.setName(cursor.getString(cursor.getColumnIndexOrThrow(KEY_NAME))); - profile.setGateway(cursor.getString(cursor.getColumnIndexOrThrow(KEY_GATEWAY))); - profile.setVpnType(VpnType.fromIdentifier(cursor.getString(cursor.getColumnIndexOrThrow(KEY_VPN_TYPE)))); - profile.setUsername(cursor.getString(cursor.getColumnIndexOrThrow(KEY_USERNAME))); - profile.setPassword(cursor.getString(cursor.getColumnIndexOrThrow(KEY_PASSWORD))); - profile.setCertificateAlias(cursor.getString(cursor.getColumnIndexOrThrow(KEY_CERTIFICATE))); - profile.setUserCertificateAlias(cursor.getString(cursor.getColumnIndexOrThrow(KEY_USER_CERTIFICATE))); - profile.setMTU(getInt(cursor, cursor.getColumnIndexOrThrow(KEY_MTU))); - profile.setPort(getInt(cursor, cursor.getColumnIndexOrThrow(KEY_PORT))); - profile.setSplitTunneling(getInt(cursor, cursor.getColumnIndexOrThrow(KEY_SPLIT_TUNNELING))); - profile.setLocalId(cursor.getString(cursor.getColumnIndexOrThrow(KEY_LOCAL_ID))); - profile.setRemoteId(cursor.getString(cursor.getColumnIndexOrThrow(KEY_REMOTE_ID))); - profile.setExcludedSubnets(cursor.getString(cursor.getColumnIndexOrThrow(KEY_EXCLUDED_SUBNETS))); - profile.setIncludedSubnets(cursor.getString(cursor.getColumnIndexOrThrow(KEY_INCLUDED_SUBNETS))); - profile.setSelectedAppsHandling(getInt(cursor, cursor.getColumnIndexOrThrow(KEY_SELECTED_APPS))); - profile.setSelectedApps(cursor.getString(cursor.getColumnIndexOrThrow(KEY_SELECTED_APPS_LIST))); - profile.setNATKeepAlive(getInt(cursor, cursor.getColumnIndexOrThrow(KEY_NAT_KEEPALIVE))); - profile.setFlags(getInt(cursor, cursor.getColumnIndexOrThrow(KEY_FLAGS))); - profile.setIkeProposal(cursor.getString(cursor.getColumnIndexOrThrow(KEY_IKE_PROPOSAL))); - profile.setEspProposal(cursor.getString(cursor.getColumnIndexOrThrow(KEY_ESP_PROPOSAL))); - profile.setDnsServers(cursor.getString(cursor.getColumnIndexOrThrow(KEY_DNS_SERVERS))); - return profile; - } - - private ContentValues ContentValuesFromVpnProfile(VpnProfile profile) - { - ContentValues values = new ContentValues(); - values.put(KEY_UUID, profile.getUUID().toString()); - values.put(KEY_NAME, profile.getName()); - values.put(KEY_GATEWAY, profile.getGateway()); - values.put(KEY_VPN_TYPE, profile.getVpnType().getIdentifier()); - values.put(KEY_USERNAME, profile.getUsername()); - values.put(KEY_PASSWORD, profile.getPassword()); - values.put(KEY_CERTIFICATE, profile.getCertificateAlias()); - values.put(KEY_USER_CERTIFICATE, profile.getUserCertificateAlias()); - values.put(KEY_MTU, profile.getMTU()); - values.put(KEY_PORT, profile.getPort()); - values.put(KEY_SPLIT_TUNNELING, profile.getSplitTunneling()); - values.put(KEY_LOCAL_ID, profile.getLocalId()); - values.put(KEY_REMOTE_ID, profile.getRemoteId()); - values.put(KEY_EXCLUDED_SUBNETS, profile.getExcludedSubnets()); - values.put(KEY_INCLUDED_SUBNETS, profile.getIncludedSubnets()); - values.put(KEY_SELECTED_APPS, profile.getSelectedAppsHandling().getValue()); - values.put(KEY_SELECTED_APPS_LIST, profile.getSelectedApps()); - values.put(KEY_NAT_KEEPALIVE, profile.getNATKeepAlive()); - values.put(KEY_FLAGS, profile.getFlags()); - values.put(KEY_IKE_PROPOSAL, profile.getIkeProposal()); - values.put(KEY_ESP_PROPOSAL, profile.getEspProposal()); - values.put(KEY_DNS_SERVERS, profile.getDnsServers()); - return values; - } - - private Integer getInt(Cursor cursor, int columnIndex) - { - return cursor.isNull(columnIndex) ? null : cursor.getInt(columnIndex); - } - - private static class DbColumn - { - public final String Name; - public final String Type; - public final Integer Since; - - public DbColumn(String name, String type, Integer since) - { - Name = name; - Type = type; - Since = since; - } - } + List getAllVpnProfiles(); } diff --git a/src/frontends/android/app/src/main/java/org/strongswan/android/data/VpnProfileSource.java b/src/frontends/android/app/src/main/java/org/strongswan/android/data/VpnProfileSource.java new file mode 100644 index 0000000000..98e8794521 --- /dev/null +++ b/src/frontends/android/app/src/main/java/org/strongswan/android/data/VpnProfileSource.java @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2023 Relution GmbH + * + * Copyright (C) secunet Security Networks AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +package org.strongswan.android.data; + +import android.content.Context; +import android.database.SQLException; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +public class VpnProfileSource implements VpnProfileDataSource +{ + private final List dataSources = new ArrayList<>(); + private final VpnProfileSqlDataSource vpnProfileSqlDataSource; + + public VpnProfileSource(Context context) + { + vpnProfileSqlDataSource = new VpnProfileSqlDataSource(context); + dataSources.add(vpnProfileSqlDataSource); + } + + @Override + public VpnProfileDataSource open() throws SQLException + { + for (final VpnProfileDataSource source : dataSources) + { + source.open(); + } + return this; + } + + @Override + public void close() + { + for (final VpnProfileDataSource source : dataSources) + { + source.close(); + } + } + + @Override + public VpnProfile insertProfile(VpnProfile profile) + { + return vpnProfileSqlDataSource.insertProfile(profile); + } + + @Override + public boolean updateVpnProfile(VpnProfile profile) + { + return vpnProfileSqlDataSource.updateVpnProfile(profile); + } + + @Override + public boolean deleteVpnProfile(VpnProfile profile) + { + return vpnProfileSqlDataSource.deleteVpnProfile(profile); + } + + @Override + public VpnProfile getVpnProfile(long id) + { + for (final VpnProfileDataSource source : dataSources) + { + final VpnProfile profile = source.getVpnProfile(id); + if (profile != null) + { + return profile; + } + } + return null; + } + + @Override + public VpnProfile getVpnProfile(UUID uuid) + { + for (final VpnProfileDataSource source : dataSources) + { + final VpnProfile profile = source.getVpnProfile(uuid); + if (profile != null) + { + return profile; + } + } + return null; + } + + @Override + public List getAllVpnProfiles() + { + final List profiles = new ArrayList<>(); + + for (final VpnProfileDataSource source : dataSources) + { + profiles.addAll(source.getAllVpnProfiles()); + } + + return profiles; + } +} diff --git a/src/frontends/android/app/src/main/java/org/strongswan/android/data/VpnProfileSqlDataSource.java b/src/frontends/android/app/src/main/java/org/strongswan/android/data/VpnProfileSqlDataSource.java new file mode 100644 index 0000000000..3b5339e917 --- /dev/null +++ b/src/frontends/android/app/src/main/java/org/strongswan/android/data/VpnProfileSqlDataSource.java @@ -0,0 +1,433 @@ +/* + * Copyright (C) 2012-2019 Tobias Brunner + * Copyright (C) 2012 Giuliano Grassi + * Copyright (C) 2012 Ralf Sager + * + * Copyright (C) secunet Security Networks AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +package org.strongswan.android.data; + +import android.content.ContentValues; +import android.content.Context; +import android.database.Cursor; +import android.database.SQLException; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; +import android.database.sqlite.SQLiteQueryBuilder; +import android.util.Log; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +public class VpnProfileSqlDataSource implements VpnProfileDataSource +{ + private static final String TAG = VpnProfileSqlDataSource.class.getSimpleName(); + + private static final DbColumn[] COLUMNS = new VpnProfileSqlDataSource.DbColumn[]{ + new VpnProfileSqlDataSource.DbColumn(KEY_ID, "INTEGER PRIMARY KEY AUTOINCREMENT", 1), + new VpnProfileSqlDataSource.DbColumn(KEY_UUID, "TEXT UNIQUE", 9), + new VpnProfileSqlDataSource.DbColumn(KEY_NAME, "TEXT NOT NULL", 1), + new VpnProfileSqlDataSource.DbColumn(KEY_GATEWAY, "TEXT NOT NULL", 1), + new VpnProfileSqlDataSource.DbColumn(KEY_VPN_TYPE, "TEXT NOT NULL", 3), + new VpnProfileSqlDataSource.DbColumn(KEY_USERNAME, "TEXT", 1), + new VpnProfileSqlDataSource.DbColumn(KEY_PASSWORD, "TEXT", 1), + new VpnProfileSqlDataSource.DbColumn(KEY_CERTIFICATE, "TEXT", 1), + new VpnProfileSqlDataSource.DbColumn(KEY_USER_CERTIFICATE, "TEXT", 2), + new VpnProfileSqlDataSource.DbColumn(KEY_MTU, "INTEGER", 5), + new VpnProfileSqlDataSource.DbColumn(KEY_PORT, "INTEGER", 5), + new VpnProfileSqlDataSource.DbColumn(KEY_SPLIT_TUNNELING, "INTEGER", 7), + new VpnProfileSqlDataSource.DbColumn(KEY_LOCAL_ID, "TEXT", 8), + new VpnProfileSqlDataSource.DbColumn(KEY_REMOTE_ID, "TEXT", 8), + new VpnProfileSqlDataSource.DbColumn(KEY_EXCLUDED_SUBNETS, "TEXT", 10), + new VpnProfileSqlDataSource.DbColumn(KEY_INCLUDED_SUBNETS, "TEXT", 11), + new VpnProfileSqlDataSource.DbColumn(KEY_SELECTED_APPS, "INTEGER", 12), + new VpnProfileSqlDataSource.DbColumn(KEY_SELECTED_APPS_LIST, "TEXT", 12), + new VpnProfileSqlDataSource.DbColumn(KEY_NAT_KEEPALIVE, "INTEGER", 13), + new VpnProfileSqlDataSource.DbColumn(KEY_FLAGS, "INTEGER", 14), + new VpnProfileSqlDataSource.DbColumn(KEY_IKE_PROPOSAL, "TEXT", 15), + new VpnProfileSqlDataSource.DbColumn(KEY_ESP_PROPOSAL, "TEXT", 15), + new VpnProfileSqlDataSource.DbColumn(KEY_DNS_SERVERS, "TEXT", 17), + }; + + private DatabaseHelper mDbHelper; + private SQLiteDatabase mDatabase; + private final Context mContext; + + private static final String DATABASE_NAME = "strongswan.db"; + private static final String TABLE_VPNPROFILE = "vpnprofile"; + + private static final int DATABASE_VERSION = 17; + + private static final String[] ALL_COLUMNS = getColumns(DATABASE_VERSION); + + private static String getDatabaseCreate(int version) + { + boolean first = true; + StringBuilder create = new StringBuilder("CREATE TABLE "); + create.append(TABLE_VPNPROFILE); + create.append(" ("); + for (DbColumn column : COLUMNS) + { + if (column.Since <= version) + { + if (!first) + { + create.append(","); + } + first = false; + create.append(column.Name); + create.append(" "); + create.append(column.Type); + } + } + create.append(");"); + return create.toString(); + } + + private static String[] getColumns(int version) + { + ArrayList columns = new ArrayList<>(); + for (DbColumn column : COLUMNS) + { + if (column.Since <= version) + { + columns.add(column.Name); + } + } + return columns.toArray(new String[0]); + } + + private static class DatabaseHelper extends SQLiteOpenHelper + { + public DatabaseHelper(Context context) + { + super(context, DATABASE_NAME, null, DATABASE_VERSION); + } + + @Override + public void onCreate(SQLiteDatabase database) + { + database.execSQL(getDatabaseCreate(DATABASE_VERSION)); + } + + @Override + public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) + { + Log.w(TAG, "Upgrading database from version " + oldVersion + + " to " + newVersion); + if (oldVersion < 2) + { + db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " ADD " + KEY_USER_CERTIFICATE + + " TEXT;"); + } + if (oldVersion < 3) + { + db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " ADD " + KEY_VPN_TYPE + + " TEXT DEFAULT '';"); + } + if (oldVersion < 4) + { /* remove NOT NULL constraint from username column */ + updateColumns(db, 4); + } + if (oldVersion < 5) + { + db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " ADD " + KEY_MTU + + " INTEGER;"); + } + if (oldVersion < 6) + { + db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " ADD " + KEY_PORT + + " INTEGER;"); + } + if (oldVersion < 7) + { + db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " ADD " + KEY_SPLIT_TUNNELING + + " INTEGER;"); + } + if (oldVersion < 8) + { + db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " ADD " + KEY_LOCAL_ID + + " TEXT;"); + db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " ADD " + KEY_REMOTE_ID + + " TEXT;"); + } + if (oldVersion < 9) + { + db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " ADD " + KEY_UUID + + " TEXT;"); + updateColumns(db, 9); + } + if (oldVersion < 10) + { + db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " ADD " + KEY_EXCLUDED_SUBNETS + + " TEXT;"); + } + if (oldVersion < 11) + { + db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " ADD " + KEY_INCLUDED_SUBNETS + + " TEXT;"); + } + if (oldVersion < 12) + { + db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " ADD " + KEY_SELECTED_APPS + + " INTEGER;"); + db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " ADD " + KEY_SELECTED_APPS_LIST + + " TEXT;"); + } + if (oldVersion < 13) + { + db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " ADD " + KEY_NAT_KEEPALIVE + + " INTEGER;"); + } + if (oldVersion < 14) + { + db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " ADD " + KEY_FLAGS + + " INTEGER;"); + } + if (oldVersion < 15) + { + db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " ADD " + KEY_IKE_PROPOSAL + + " TEXT;"); + db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " ADD " + KEY_ESP_PROPOSAL + + " TEXT;"); + } + if (oldVersion < 16) + { /* add a UUID to all entries that haven't one yet */ + db.beginTransaction(); + try + { + Cursor cursor = db.query(TABLE_VPNPROFILE, getColumns(16), KEY_UUID + " is NULL", null, null, null, null); + for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) + { + ContentValues values = new ContentValues(); + values.put(KEY_UUID, UUID.randomUUID().toString()); + db.update(TABLE_VPNPROFILE, values, KEY_ID + " = " + cursor.getLong(cursor.getColumnIndexOrThrow(KEY_ID)), null); + } + cursor.close(); + db.setTransactionSuccessful(); + } + finally + { + db.endTransaction(); + } + } + if (oldVersion < 17) + { + db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " ADD " + KEY_DNS_SERVERS + + " TEXT;"); + } + } + + private void updateColumns(SQLiteDatabase db, int version) + { + db.beginTransaction(); + try + { + db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " RENAME TO tmp_" + TABLE_VPNPROFILE + ";"); + db.execSQL(getDatabaseCreate(version)); + StringBuilder insert = new StringBuilder("INSERT INTO " + TABLE_VPNPROFILE + " SELECT "); + SQLiteQueryBuilder.appendColumns(insert, getColumns(version)); + db.execSQL(insert.append(" FROM tmp_" + TABLE_VPNPROFILE + ";").toString()); + db.execSQL("DROP TABLE tmp_" + TABLE_VPNPROFILE + ";"); + db.setTransactionSuccessful(); + } + finally + { + db.endTransaction(); + } + } + } + + /** + * Construct a new VPN profile data source. The context is used to + * open/create the database. + * + * @param context context used to access the database + */ + public VpnProfileSqlDataSource(Context context) + { + this.mContext = context; + } + + @Override + public VpnProfileDataSource open() throws SQLException + { + if (mDbHelper == null) + { + mDbHelper = new DatabaseHelper(mContext); + mDatabase = mDbHelper.getWritableDatabase(); + } + return this; + } + + @Override + public void close() + { + if (mDbHelper != null) + { + mDbHelper.close(); + mDbHelper = null; + } + } + + @Override + public VpnProfile insertProfile(VpnProfile profile) + { + ContentValues values = ContentValuesFromVpnProfile(profile); + long insertId = mDatabase.insert(TABLE_VPNPROFILE, null, values); + if (insertId == -1) + { + return null; + } + profile.setId(insertId); + return profile; + } + + @Override + public boolean updateVpnProfile(VpnProfile profile) + { + long id = profile.getId(); + ContentValues values = ContentValuesFromVpnProfile(profile); + return mDatabase.update(TABLE_VPNPROFILE, values, KEY_ID + " = " + id, null) > 0; + } + + @Override + public boolean deleteVpnProfile(VpnProfile profile) + { + long id = profile.getId(); + return mDatabase.delete(TABLE_VPNPROFILE, KEY_ID + " = " + id, null) > 0; + } + + @Override + public VpnProfile getVpnProfile(long id) + { + VpnProfile profile = null; + Cursor cursor = mDatabase.query(TABLE_VPNPROFILE, ALL_COLUMNS, + KEY_ID + "=" + id, null, null, null, null); + if (cursor.moveToFirst()) + { + profile = VpnProfileFromCursor(cursor); + } + cursor.close(); + return profile; + } + + @Override + public VpnProfile getVpnProfile(UUID uuid) + { + VpnProfile profile = null; + Cursor cursor = mDatabase.query(TABLE_VPNPROFILE, ALL_COLUMNS, + KEY_UUID + "='" + uuid.toString() + "'", null, null, null, null); + if (cursor.moveToFirst()) + { + profile = VpnProfileFromCursor(cursor); + } + cursor.close(); + return profile; + } + + @Override + public List getAllVpnProfiles() + { + List vpnProfiles = new ArrayList(); + + Cursor cursor = mDatabase.query(TABLE_VPNPROFILE, ALL_COLUMNS, null, null, null, null, null); + cursor.moveToFirst(); + while (!cursor.isAfterLast()) + { + VpnProfile vpnProfile = VpnProfileFromCursor(cursor); + vpnProfiles.add(vpnProfile); + cursor.moveToNext(); + } + cursor.close(); + return vpnProfiles; + } + + private VpnProfile VpnProfileFromCursor(Cursor cursor) + { + VpnProfile profile = new VpnProfile(); + profile.setId(cursor.getLong(cursor.getColumnIndexOrThrow(KEY_ID))); + profile.setUUID(UUID.fromString(cursor.getString(cursor.getColumnIndexOrThrow(KEY_UUID)))); + profile.setName(cursor.getString(cursor.getColumnIndexOrThrow(KEY_NAME))); + profile.setGateway(cursor.getString(cursor.getColumnIndexOrThrow(KEY_GATEWAY))); + profile.setVpnType(VpnType.fromIdentifier(cursor.getString(cursor.getColumnIndexOrThrow(KEY_VPN_TYPE)))); + profile.setUsername(cursor.getString(cursor.getColumnIndexOrThrow(KEY_USERNAME))); + profile.setPassword(cursor.getString(cursor.getColumnIndexOrThrow(KEY_PASSWORD))); + profile.setCertificateAlias(cursor.getString(cursor.getColumnIndexOrThrow(KEY_CERTIFICATE))); + profile.setUserCertificateAlias(cursor.getString(cursor.getColumnIndexOrThrow(KEY_USER_CERTIFICATE))); + profile.setMTU(getInt(cursor, cursor.getColumnIndexOrThrow(KEY_MTU))); + profile.setPort(getInt(cursor, cursor.getColumnIndexOrThrow(KEY_PORT))); + profile.setSplitTunneling(getInt(cursor, cursor.getColumnIndexOrThrow(KEY_SPLIT_TUNNELING))); + profile.setLocalId(cursor.getString(cursor.getColumnIndexOrThrow(KEY_LOCAL_ID))); + profile.setRemoteId(cursor.getString(cursor.getColumnIndexOrThrow(KEY_REMOTE_ID))); + profile.setExcludedSubnets(cursor.getString(cursor.getColumnIndexOrThrow(KEY_EXCLUDED_SUBNETS))); + profile.setIncludedSubnets(cursor.getString(cursor.getColumnIndexOrThrow(KEY_INCLUDED_SUBNETS))); + profile.setSelectedAppsHandling(getInt(cursor, cursor.getColumnIndexOrThrow(KEY_SELECTED_APPS))); + profile.setSelectedApps(cursor.getString(cursor.getColumnIndexOrThrow(KEY_SELECTED_APPS_LIST))); + profile.setNATKeepAlive(getInt(cursor, cursor.getColumnIndexOrThrow(KEY_NAT_KEEPALIVE))); + profile.setFlags(getInt(cursor, cursor.getColumnIndexOrThrow(KEY_FLAGS))); + profile.setIkeProposal(cursor.getString(cursor.getColumnIndexOrThrow(KEY_IKE_PROPOSAL))); + profile.setEspProposal(cursor.getString(cursor.getColumnIndexOrThrow(KEY_ESP_PROPOSAL))); + profile.setDnsServers(cursor.getString(cursor.getColumnIndexOrThrow(KEY_DNS_SERVERS))); + return profile; + } + + private ContentValues ContentValuesFromVpnProfile(VpnProfile profile) + { + ContentValues values = new ContentValues(); + values.put(KEY_UUID, profile.getUUID().toString()); + values.put(KEY_NAME, profile.getName()); + values.put(KEY_GATEWAY, profile.getGateway()); + values.put(KEY_VPN_TYPE, profile.getVpnType().getIdentifier()); + values.put(KEY_USERNAME, profile.getUsername()); + values.put(KEY_PASSWORD, profile.getPassword()); + values.put(KEY_CERTIFICATE, profile.getCertificateAlias()); + values.put(KEY_USER_CERTIFICATE, profile.getUserCertificateAlias()); + values.put(KEY_MTU, profile.getMTU()); + values.put(KEY_PORT, profile.getPort()); + values.put(KEY_SPLIT_TUNNELING, profile.getSplitTunneling()); + values.put(KEY_LOCAL_ID, profile.getLocalId()); + values.put(KEY_REMOTE_ID, profile.getRemoteId()); + values.put(KEY_EXCLUDED_SUBNETS, profile.getExcludedSubnets()); + values.put(KEY_INCLUDED_SUBNETS, profile.getIncludedSubnets()); + values.put(KEY_SELECTED_APPS, profile.getSelectedAppsHandling().getValue()); + values.put(KEY_SELECTED_APPS_LIST, profile.getSelectedApps()); + values.put(KEY_NAT_KEEPALIVE, profile.getNATKeepAlive()); + values.put(KEY_FLAGS, profile.getFlags()); + values.put(KEY_IKE_PROPOSAL, profile.getIkeProposal()); + values.put(KEY_ESP_PROPOSAL, profile.getEspProposal()); + values.put(KEY_DNS_SERVERS, profile.getDnsServers()); + return values; + } + + private Integer getInt(Cursor cursor, int columnIndex) + { + return cursor.isNull(columnIndex) ? null : cursor.getInt(columnIndex); + } + + private static class DbColumn + { + public final String Name; + public final String Type; + public final Integer Since; + + public DbColumn(String name, String type, Integer since) + { + Name = name; + Type = type; + Since = since; + } + } +} diff --git a/src/frontends/android/app/src/main/java/org/strongswan/android/logic/CharonVpnService.java b/src/frontends/android/app/src/main/java/org/strongswan/android/logic/CharonVpnService.java index 5f5b2a1879..115ff7cec4 100644 --- a/src/frontends/android/app/src/main/java/org/strongswan/android/logic/CharonVpnService.java +++ b/src/frontends/android/app/src/main/java/org/strongswan/android/logic/CharonVpnService.java @@ -45,6 +45,7 @@ import org.strongswan.android.R; import org.strongswan.android.data.VpnProfile; import org.strongswan.android.data.VpnProfile.SelectedAppsHandling; import org.strongswan.android.data.VpnProfileDataSource; +import org.strongswan.android.data.VpnProfileSource; import org.strongswan.android.data.VpnType.VpnTypeFeature; import org.strongswan.android.logic.VpnStateService.ErrorState; import org.strongswan.android.logic.VpnStateService.State; @@ -196,7 +197,7 @@ public class CharonVpnService extends VpnService implements Runnable, VpnStateSe /* handler used to do changes in the main UI thread */ mHandler = new Handler(getMainLooper()); - mDataSource = new VpnProfileDataSource(this); + mDataSource = new VpnProfileSource(this); mDataSource.open(); /* use a separate thread as main thread for charon */ mConnectionHandler = new Thread(this); diff --git a/src/frontends/android/app/src/main/java/org/strongswan/android/ui/SettingsFragment.java b/src/frontends/android/app/src/main/java/org/strongswan/android/ui/SettingsFragment.java index 98e3992565..7f047ce6b4 100644 --- a/src/frontends/android/app/src/main/java/org/strongswan/android/ui/SettingsFragment.java +++ b/src/frontends/android/app/src/main/java/org/strongswan/android/ui/SettingsFragment.java @@ -16,6 +16,9 @@ package org.strongswan.android.ui; +import static org.strongswan.android.utils.Constants.PREF_DEFAULT_VPN_PROFILE; +import static org.strongswan.android.utils.Constants.PREF_DEFAULT_VPN_PROFILE_MRU; + import android.content.SharedPreferences; import android.os.Build; import android.os.Bundle; @@ -23,6 +26,7 @@ import android.os.Bundle; import org.strongswan.android.R; import org.strongswan.android.data.VpnProfile; import org.strongswan.android.data.VpnProfileDataSource; +import org.strongswan.android.data.VpnProfileSource; import java.util.ArrayList; import java.util.Collections; @@ -34,9 +38,6 @@ import androidx.preference.Preference; import androidx.preference.PreferenceFragmentCompat; import androidx.preference.PreferenceManager; -import static org.strongswan.android.utils.Constants.PREF_DEFAULT_VPN_PROFILE; -import static org.strongswan.android.utils.Constants.PREF_DEFAULT_VPN_PROFILE_MRU; - public class SettingsFragment extends PreferenceFragmentCompat implements Preference.OnPreferenceChangeListener { private ListPreference mDefaultVPNProfile; @@ -46,7 +47,7 @@ public class SettingsFragment extends PreferenceFragmentCompat implements Prefer { setPreferencesFromResource(R.xml.settings, s); - mDefaultVPNProfile = (ListPreference)findPreference(PREF_DEFAULT_VPN_PROFILE); + mDefaultVPNProfile = findPreference(PREF_DEFAULT_VPN_PROFILE); mDefaultVPNProfile.setOnPreferenceChangeListener(this); if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) { @@ -59,11 +60,12 @@ public class SettingsFragment extends PreferenceFragmentCompat implements Prefer { super.onResume(); - VpnProfileDataSource profiles = new VpnProfileDataSource(getActivity()); + VpnProfileDataSource profiles = new VpnProfileSource(getActivity()); profiles.open(); List all = profiles.getAllVpnProfiles(); - Collections.sort(all, new Comparator() { + Collections.sort(all, new Comparator() + { @Override public int compare(VpnProfile lhs, VpnProfile rhs) { @@ -111,7 +113,7 @@ public class SettingsFragment extends PreferenceFragmentCompat implements Prefer private void setCurrentProfileName(String uuid) { - VpnProfileDataSource profiles = new VpnProfileDataSource(getActivity()); + VpnProfileDataSource profiles = new VpnProfileSource(getActivity()); profiles.open(); if (!uuid.equals(PREF_DEFAULT_VPN_PROFILE_MRU)) diff --git a/src/frontends/android/app/src/main/java/org/strongswan/android/ui/VpnProfileControlActivity.java b/src/frontends/android/app/src/main/java/org/strongswan/android/ui/VpnProfileControlActivity.java index 1913bbb5f3..fb83c4e10c 100644 --- a/src/frontends/android/app/src/main/java/org/strongswan/android/ui/VpnProfileControlActivity.java +++ b/src/frontends/android/app/src/main/java/org/strongswan/android/ui/VpnProfileControlActivity.java @@ -42,12 +42,12 @@ import android.widget.Toast; import org.strongswan.android.R; import org.strongswan.android.data.VpnProfile; import org.strongswan.android.data.VpnProfileDataSource; +import org.strongswan.android.data.VpnProfileSource; import org.strongswan.android.data.VpnType.VpnTypeFeature; import org.strongswan.android.logic.VpnStateService; import org.strongswan.android.logic.VpnStateService.State; import org.strongswan.android.utils.Constants; -import androidx.activity.result.ActivityResultCallback; import androidx.activity.result.ActivityResultLauncher; import androidx.activity.result.contract.ActivityResultContracts; import androidx.annotation.NonNull; @@ -257,6 +257,7 @@ public class VpnProfileControlActivity extends AppCompatActivity /** * Check if we have permission to display notifications to the user, if necessary, * ask the user to allow this. + * * @return true if profile can be initiated immediately */ private boolean checkNotificationPermission() @@ -274,6 +275,7 @@ public class VpnProfileControlActivity extends AppCompatActivity /** * Check if we are on the system's power whitelist, if necessary, or ask the user * to add us. + * * @return true if profile can be initiated immediately */ private boolean checkPowerWhitelist() @@ -373,7 +375,7 @@ public class VpnProfileControlActivity extends AppCompatActivity { VpnProfile profile = null; - VpnProfileDataSource dataSource = new VpnProfileDataSource(this); + VpnProfileDataSource dataSource = new VpnProfileSource(this); dataSource.open(); String profileUUID = intent.getStringExtra(EXTRA_VPN_PROFILE_ID); if (profileUUID != null) @@ -415,7 +417,7 @@ public class VpnProfileControlActivity extends AppCompatActivity String profileUUID = intent.getStringExtra(EXTRA_VPN_PROFILE_ID); if (profileUUID != null) { - VpnProfileDataSource dataSource = new VpnProfileDataSource(this); + VpnProfileDataSource dataSource = new VpnProfileSource(this); dataSource.open(); profile = dataSource.getVpnProfile(profileUUID); dataSource.close(); @@ -583,9 +585,9 @@ public class VpnProfileControlActivity extends AppCompatActivity final Bundle profileInfo = getArguments(); LayoutInflater inflater = getActivity().getLayoutInflater(); View view = inflater.inflate(R.layout.login_dialog, null); - EditText username = (EditText)view.findViewById(R.id.username); + EditText username = view.findViewById(R.id.username); username.setText(profileInfo.getString(VpnProfileDataSource.KEY_USERNAME)); - final EditText password = (EditText)view.findViewById(R.id.password); + final EditText password = view.findViewById(R.id.password); AlertDialog.Builder adb = new AlertDialog.Builder(getActivity()); adb.setView(view); diff --git a/src/frontends/android/app/src/main/java/org/strongswan/android/ui/VpnProfileDetailActivity.java b/src/frontends/android/app/src/main/java/org/strongswan/android/ui/VpnProfileDetailActivity.java index 85d178e52f..8fd12338f7 100644 --- a/src/frontends/android/app/src/main/java/org/strongswan/android/ui/VpnProfileDetailActivity.java +++ b/src/frontends/android/app/src/main/java/org/strongswan/android/ui/VpnProfileDetailActivity.java @@ -56,6 +56,7 @@ import org.strongswan.android.R; import org.strongswan.android.data.VpnProfile; import org.strongswan.android.data.VpnProfile.SelectedAppsHandling; import org.strongswan.android.data.VpnProfileDataSource; +import org.strongswan.android.data.VpnProfileSource; import org.strongswan.android.data.VpnType; import org.strongswan.android.data.VpnType.VpnTypeFeature; import org.strongswan.android.logic.StrongSwanApplication; @@ -188,7 +189,7 @@ public class VpnProfileDetailActivity extends AppCompatActivity /* the title is set when we load the profile, if any */ getSupportActionBar().setDisplayHomeAsUpEnabled(true); - mDataSource = new VpnProfileDataSource(this); + mDataSource = new VpnProfileSource(this); mDataSource.open(); setContentView(R.layout.profile_detail_view); diff --git a/src/frontends/android/app/src/main/java/org/strongswan/android/ui/VpnProfileImportActivity.java b/src/frontends/android/app/src/main/java/org/strongswan/android/ui/VpnProfileImportActivity.java index c58365d9cd..3f7c51c19c 100644 --- a/src/frontends/android/app/src/main/java/org/strongswan/android/ui/VpnProfileImportActivity.java +++ b/src/frontends/android/app/src/main/java/org/strongswan/android/ui/VpnProfileImportActivity.java @@ -45,6 +45,7 @@ import org.strongswan.android.R; import org.strongswan.android.data.VpnProfile; import org.strongswan.android.data.VpnProfile.SelectedAppsHandling; import org.strongswan.android.data.VpnProfileDataSource; +import org.strongswan.android.data.VpnProfileSource; import org.strongswan.android.data.VpnType; import org.strongswan.android.data.VpnType.VpnTypeFeature; import org.strongswan.android.logic.TrustedCertificateManager; @@ -184,7 +185,7 @@ public class VpnProfileImportActivity extends AppCompatActivity getSupportActionBar().setHomeAsUpIndicator(R.drawable.ic_close_white_24dp); getSupportActionBar().setDisplayHomeAsUpEnabled(true); - mDataSource = new VpnProfileDataSource(this); + mDataSource = new VpnProfileSource(this); mDataSource.open(); setContentView(R.layout.profile_import_view); diff --git a/src/frontends/android/app/src/main/java/org/strongswan/android/ui/VpnProfileListFragment.java b/src/frontends/android/app/src/main/java/org/strongswan/android/ui/VpnProfileListFragment.java index 291a4fceac..a4ed193083 100644 --- a/src/frontends/android/app/src/main/java/org/strongswan/android/ui/VpnProfileListFragment.java +++ b/src/frontends/android/app/src/main/java/org/strongswan/android/ui/VpnProfileListFragment.java @@ -41,6 +41,7 @@ import android.widget.Toast; import org.strongswan.android.R; import org.strongswan.android.data.VpnProfile; import org.strongswan.android.data.VpnProfileDataSource; +import org.strongswan.android.data.VpnProfileSource; import org.strongswan.android.ui.adapter.VpnProfileAdapter; import org.strongswan.android.utils.Constants; @@ -65,12 +66,14 @@ public class VpnProfileListFragment extends Fragment private HashSet mSelected; private boolean mReadOnly; - private BroadcastReceiver mProfilesChanged = new BroadcastReceiver() + private final BroadcastReceiver mProfilesChanged = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { - long id, ids[]; + long id; + long[] ids; + if ((id = intent.getLongExtra(Constants.VPN_PROFILES_SINGLE, 0)) > 0) { VpnProfile profile = mDataSource.getVpnProfile(id); @@ -104,7 +107,8 @@ public class VpnProfileListFragment extends Fragment /** * The activity containing this fragment should implement this interface */ - public interface OnVpnProfileSelectedListener { + public interface OnVpnProfileSelectedListener + { void onVpnProfileSelected(VpnProfile profile); } @@ -159,7 +163,7 @@ public class VpnProfileListFragment extends Fragment mSelected = selected != null ? new HashSet<>(selected) : new HashSet<>(); } - mDataSource = new VpnProfileDataSource(this.getActivity()); + mDataSource = new VpnProfileSource(this.getActivity()); mDataSource.open(); /* cached list of profiles used as backend for the ListView */ @@ -206,19 +210,18 @@ public class VpnProfileListFragment extends Fragment @Override public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) + if (item.getItemId() == R.id.add_profile) { - case R.id.add_profile: - Intent connectionIntent = new Intent(getActivity(), - VpnProfileDetailActivity.class); - startActivity(connectionIntent); - return true; - default: - return super.onOptionsItemSelected(item); + Intent connectionIntent = new Intent(getActivity(), + VpnProfileDetailActivity.class); + startActivity(connectionIntent); + return true; } + return super.onOptionsItemSelected(item); } - private final OnItemClickListener mVpnProfileClicked = new OnItemClickListener() { + private final OnItemClickListener mVpnProfileClicked = new OnItemClickListener() + { @Override public void onItemClick(AdapterView a, View v, int position, long id) { @@ -229,7 +232,8 @@ public class VpnProfileListFragment extends Fragment } }; - private final MultiChoiceModeListener mVpnProfileSelected = new MultiChoiceModeListener() { + private final MultiChoiceModeListener mVpnProfileSelected = new MultiChoiceModeListener() + { private MenuItem mEditProfile; private MenuItem mCopyProfile; @@ -297,7 +301,7 @@ public class VpnProfileListFragment extends Fragment { profiles.add((VpnProfile)mListView.getItemAtPosition(position)); } - long ids[] = new long[profiles.size()]; + long[] ids = new long[profiles.size()]; for (int i = 0; i < profiles.size(); i++) { VpnProfile profile = profiles.get(i); diff --git a/src/frontends/android/app/src/main/java/org/strongswan/android/ui/VpnTileService.java b/src/frontends/android/app/src/main/java/org/strongswan/android/ui/VpnTileService.java index 2e128962d2..6178c59ba6 100644 --- a/src/frontends/android/app/src/main/java/org/strongswan/android/ui/VpnTileService.java +++ b/src/frontends/android/app/src/main/java/org/strongswan/android/ui/VpnTileService.java @@ -32,6 +32,7 @@ import android.service.quicksettings.TileService; import org.strongswan.android.R; import org.strongswan.android.data.VpnProfile; import org.strongswan.android.data.VpnProfileDataSource; +import org.strongswan.android.data.VpnProfileSource; import org.strongswan.android.data.VpnType; import org.strongswan.android.logic.VpnStateService; import org.strongswan.android.utils.Constants; @@ -73,7 +74,7 @@ public class VpnTileService extends TileService implements VpnStateService.VpnSt context.bindService(new Intent(context, VpnStateService.class), mServiceConnection, Service.BIND_AUTO_CREATE); - mDataSource = new VpnProfileDataSource(this); + mDataSource = new VpnProfileSource(this); mDataSource.open(); } -- 2.47.2