android: Always use UUID to access profiles

Use the UUID rather than the ID to ensure there are no conflicts between
profiles from the database and managed profiles.
This commit is contained in:
Markus Pfeiffer 2023-11-21 15:37:22 +01:00 committed by Tobias Brunner
parent d629e1d358
commit 8e3b921abe
13 changed files with 80 additions and 106 deletions

View File

@ -22,6 +22,7 @@ package org.strongswan.android.data;
import android.text.TextUtils;
import java.util.Arrays;
import java.util.Objects;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.UUID;
@ -339,16 +340,22 @@ public class VpnProfile implements Cloneable
@Override
public boolean equals(Object o)
{
if (o != null && o instanceof VpnProfile)
if (o == this)
{
VpnProfile other = (VpnProfile)o;
if (this.mUUID != null && other.getUUID() != null)
{
return this.mUUID.equals(other.getUUID());
}
return this.mId == other.getId();
return true;
}
return false;
if (o == null || getClass() != o.getClass())
{
return false;
}
VpnProfile that = (VpnProfile)o;
return Objects.equals(mUUID, that.mUUID);
}
@Override
public int hashCode()
{
return Objects.hash(mUUID);
}
@Override

View File

@ -89,14 +89,6 @@ public interface VpnProfileDataSource
*/
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
*/
VpnProfile getVpnProfile(long id);
/**
* Get a single VPN profile from the database by its UUID.
*

View File

@ -71,20 +71,6 @@ public class VpnProfileSource implements VpnProfileDataSource
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)
{

View File

@ -298,30 +298,16 @@ public class VpnProfileSqlDataSource implements VpnProfileDataSource
@Override
public boolean updateVpnProfile(VpnProfile profile)
{
long id = profile.getId();
final UUID uuid = profile.getUUID();
ContentValues values = ContentValuesFromVpnProfile(profile);
return mDatabase.update(TABLE_VPNPROFILE, values, KEY_ID + " = " + id, null) > 0;
return mDatabase.update(TABLE_VPNPROFILE, values, KEY_UUID + " = ?", new String[]{uuid.toString()}) > 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;
final UUID uuid = profile.getUUID();
return mDatabase.delete(TABLE_VPNPROFILE, KEY_UUID + " = ?", new String[]{uuid.toString()}) > 0;
}
@Override
@ -358,7 +344,6 @@ public class VpnProfileSqlDataSource implements VpnProfileDataSource
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)));

View File

@ -462,7 +462,7 @@ public class CharonVpnService extends VpnService implements Runnable, VpnStateSe
Intent intent = new Intent(getApplicationContext(), VpnProfileControlActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setAction(VpnProfileControlActivity.START_PROFILE);
intent.putExtra(VpnProfileControlActivity.EXTRA_VPN_PROFILE_ID, profile.getUUID().toString());
intent.putExtra(VpnProfileControlActivity.EXTRA_VPN_PROFILE_UUID, profile.getUUID().toString());
int flags = PendingIntent.FLAG_UPDATE_CURRENT;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
{

View File

@ -55,11 +55,11 @@ public class VpnStateService extends Service
private ErrorState mError = ErrorState.NO_ERROR;
private ImcState mImcState = ImcState.UNKNOWN;
private final LinkedList<RemediationInstruction> mRemediationInstructions = new LinkedList<RemediationInstruction>();
private static long RETRY_INTERVAL = 1000;
private static final long RETRY_INTERVAL = 1000;
/* cap the retry interval at 2 minutes */
private static long MAX_RETRY_INTERVAL = 120000;
private static int RETRY_MSG = 1;
private RetryTimeoutProvider mTimeoutProvider = new RetryTimeoutProvider();
private static final long MAX_RETRY_INTERVAL = 120000;
private static final int RETRY_MSG = 1;
private final RetryTimeoutProvider mTimeoutProvider = new RetryTimeoutProvider();
private long mRetryTimeout;
private long mRetryIn;
@ -89,7 +89,7 @@ public class VpnStateService extends Service
*/
public interface VpnStateListener
{
public void stateChanged();
void stateChanged();
}
/**
@ -169,6 +169,7 @@ public class VpnStateService extends Service
/**
* Get the total number of seconds until there is an automatic retry to reconnect.
*
* @return total number of seconds until the retry
*/
public int getRetryTimeout()
@ -178,6 +179,7 @@ public class VpnStateService extends Service
/**
* Get the number of seconds until there is an automatic retry to reconnect.
*
* @return number of seconds until the retry
*/
public int getRetryIn()
@ -283,8 +285,9 @@ public class VpnStateService extends Service
/**
* Connect (or reconnect) a profile
*
* @param profileInfo optional profile info (basically the UUID and password), taken from the
* previous profile if null
* previous profile if null
* @param fromScratch true if this is a manual retry/reconnect or a completely new connection
*/
public void connect(Bundle profileInfo, boolean fromScratch)
@ -330,7 +333,7 @@ public class VpnStateService extends Service
Intent intent = new Intent(this, VpnProfileControlActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setAction(VpnProfileControlActivity.START_PROFILE);
intent.putExtra(VpnProfileControlActivity.EXTRA_VPN_PROFILE_ID, mProfile.getUUID().toString());
intent.putExtra(VpnProfileControlActivity.EXTRA_VPN_PROFILE_UUID, mProfile.getUUID().toString());
startActivity(intent);
/* reset the retry timer immediately in case the user needs more time to enter the password */
notifyListeners(() -> {
@ -353,7 +356,8 @@ public class VpnStateService extends Service
*/
private void notifyListeners(final Callable<Boolean> change)
{
mHandler.post(new Runnable() {
mHandler.post(new Runnable()
{
@Override
public void run()
{
@ -386,7 +390,8 @@ public class VpnStateService extends Service
*/
public void startConnection(final VpnProfile profile)
{
notifyListeners(new Callable<Boolean>() {
notifyListeners(new Callable<Boolean>()
{
@Override
public Boolean call() throws Exception
{
@ -411,7 +416,8 @@ public class VpnStateService extends Service
*/
public void setState(final State state)
{
notifyListeners(new Callable<Boolean>() {
notifyListeners(new Callable<Boolean>()
{
@Override
public Boolean call() throws Exception
{
@ -438,7 +444,8 @@ public class VpnStateService extends Service
*/
public void setError(final ErrorState error)
{
notifyListeners(new Callable<Boolean>() {
notifyListeners(new Callable<Boolean>()
{
@Override
public Boolean call() throws Exception
{
@ -471,7 +478,8 @@ public class VpnStateService extends Service
*/
public void setImcState(final ImcState state)
{
notifyListeners(new Callable<Boolean>() {
notifyListeners(new Callable<Boolean>()
{
@Override
public Boolean call() throws Exception
{
@ -501,7 +509,8 @@ public class VpnStateService extends Service
*/
public void addRemediationInstruction(final RemediationInstruction instruction)
{
mHandler.post(new Runnable() {
mHandler.post(new Runnable()
{
@Override
public void run()
{
@ -535,7 +544,8 @@ public class VpnStateService extends Service
/**
* Special Handler subclass that handles the retry countdown (more accurate than CountDownTimer)
*/
private static class RetryHandler extends Handler {
private static class RetryHandler extends Handler
{
WeakReference<VpnStateService> mService;
public RetryHandler(Looper looper, VpnStateService service)
@ -604,6 +614,7 @@ public class VpnStateService extends Service
/**
* Called each time a new retry timeout is started. The timeout increases until reset() is
* called and the base timeout is returned again.
*
* @param error Error state
*/
public long getTimeout(ErrorState error)

View File

@ -115,7 +115,7 @@ public class MainActivity extends AppCompatActivity implements OnVpnProfileSelec
{
Intent intent = new Intent(this, VpnProfileControlActivity.class);
intent.setAction(VpnProfileControlActivity.START_PROFILE);
intent.putExtra(VpnProfileControlActivity.EXTRA_VPN_PROFILE_ID, profile.getUUID().toString());
intent.putExtra(VpnProfileControlActivity.EXTRA_VPN_PROFILE_UUID, profile.getUUID().toString());
startActivity(intent);
}

View File

@ -64,7 +64,7 @@ public class VpnProfileControlActivity extends AppCompatActivity
{
public static final String START_PROFILE = "org.strongswan.android.action.START_PROFILE";
public static final String DISCONNECT = "org.strongswan.android.action.DISCONNECT";
public static final String EXTRA_VPN_PROFILE_ID = "org.strongswan.android.VPN_PROFILE_ID";
public static final String EXTRA_VPN_PROFILE_UUID = "org.strongswan.android.VPN_PROFILE_UUID";
private static final String WAITING_FOR_RESULT = "WAITING_FOR_RESULT";
private static final String PROFILE_NAME = "PROFILE_NAME";
@ -377,19 +377,11 @@ public class VpnProfileControlActivity extends AppCompatActivity
VpnProfileDataSource dataSource = new VpnProfileSource(this);
dataSource.open();
String profileUUID = intent.getStringExtra(EXTRA_VPN_PROFILE_ID);
String profileUUID = intent.getStringExtra(EXTRA_VPN_PROFILE_UUID);
if (profileUUID != null)
{
profile = dataSource.getVpnProfile(profileUUID);
}
else
{
long profileId = intent.getLongExtra(EXTRA_VPN_PROFILE_ID, 0);
if (profileId > 0)
{
profile = dataSource.getVpnProfile(profileId);
}
}
dataSource.close();
if (profile != null)
@ -414,7 +406,7 @@ public class VpnProfileControlActivity extends AppCompatActivity
removeFragmentByTag(DIALOG_TAG);
String profileUUID = intent.getStringExtra(EXTRA_VPN_PROFILE_ID);
String profileUUID = intent.getStringExtra(EXTRA_VPN_PROFILE_UUID);
if (profileUUID != null)
{
VpnProfileDataSource dataSource = new VpnProfileSource(this);

View File

@ -88,7 +88,7 @@ import androidx.localbroadcastmanager.content.LocalBroadcastManager;
public class VpnProfileDetailActivity extends AppCompatActivity
{
private VpnProfileDataSource mDataSource;
private Long mId;
private String mUuid;
private TrustedCertificateEntry mCertEntry;
private String mUserCertLoading;
private CertificateIdentitiesAdapter mSelectUserIdAdapter;
@ -380,11 +380,11 @@ public class VpnProfileDetailActivity extends AppCompatActivity
}
});
mId = savedInstanceState == null ? null : savedInstanceState.getLong(VpnProfileDataSource.KEY_ID);
if (mId == null)
mUuid = savedInstanceState == null ? null : savedInstanceState.getString(VpnProfileDataSource.KEY_UUID);
if (mUuid == null)
{
Bundle extras = getIntent().getExtras();
mId = extras == null ? null : extras.getLong(VpnProfileDataSource.KEY_ID);
mUuid = extras == null ? null : extras.getString(VpnProfileDataSource.KEY_UUID);
}
loadProfileData(savedInstanceState);
@ -406,9 +406,9 @@ public class VpnProfileDetailActivity extends AppCompatActivity
protected void onSaveInstanceState(Bundle outState)
{
super.onSaveInstanceState(outState);
if (mId != null)
if (mUuid != null)
{
outState.putLong(VpnProfileDataSource.KEY_ID, mId);
outState.putString(VpnProfileDataSource.KEY_UUID, mUuid);
}
if (mUserCertEntry != null)
{
@ -615,10 +615,10 @@ public class VpnProfileDetailActivity extends AppCompatActivity
mDataSource.insertProfile(mProfile);
}
Intent intent = new Intent(Constants.VPN_PROFILES_CHANGED);
intent.putExtra(Constants.VPN_PROFILES_SINGLE, mProfile.getId());
intent.putExtra(Constants.VPN_PROFILES_SINGLE, mProfile.getUUID().toString());
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
setResult(RESULT_OK, new Intent().putExtra(VpnProfileDataSource.KEY_ID, mProfile.getId()));
setResult(RESULT_OK, new Intent().putExtra(VpnProfileDataSource.KEY_UUID, mProfile.getUUID().toString()));
finish();
}
}
@ -757,9 +757,9 @@ public class VpnProfileDetailActivity extends AppCompatActivity
Integer flags = null;
getSupportActionBar().setTitle(R.string.add_profile);
if (mId != null && mId != 0)
if (mUuid != null)
{
mProfile = mDataSource.getVpnProfile(mId);
mProfile = mDataSource.getVpnProfile(mUuid);
if (mProfile != null)
{
mName.setText(mProfile.getName());
@ -791,7 +791,7 @@ public class VpnProfileDetailActivity extends AppCompatActivity
else
{
Log.e(VpnProfileDetailActivity.class.getSimpleName(),
"VPN profile with id " + mId + " not found");
"VPN profile with UUID " + mUuid + " not found");
finish();
}
}

View File

@ -675,7 +675,7 @@ public class VpnProfileImportActivity extends AppCompatActivity
updateProfileData();
if (mExisting != null)
{
mProfile.setId(mExisting.getId());
mProfile.setUUID(mExisting.getUUID());
mDataSource.updateVpnProfile(mProfile);
}
else
@ -697,14 +697,14 @@ public class VpnProfileImportActivity extends AppCompatActivity
}
}
Intent intent = new Intent(Constants.VPN_PROFILES_CHANGED);
intent.putExtra(Constants.VPN_PROFILES_SINGLE, mProfile.getId());
intent.putExtra(Constants.VPN_PROFILES_SINGLE, mProfile.getUUID().toString());
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
intent = new Intent(this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
setResult(RESULT_OK, new Intent().putExtra(VpnProfileDataSource.KEY_ID, mProfile.getId()));
setResult(RESULT_OK, new Intent().putExtra(VpnProfileDataSource.KEY_UUID, mProfile.getUUID().toString()));
finish();
}
}

View File

@ -49,6 +49,7 @@ import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
import androidx.fragment.app.Fragment;
@ -71,12 +72,12 @@ public class VpnProfileListFragment extends Fragment
@Override
public void onReceive(Context context, Intent intent)
{
long id;
long[] ids;
String uuid;
String[] uuids;
if ((id = intent.getLongExtra(Constants.VPN_PROFILES_SINGLE, 0)) > 0)
if ((uuid = intent.getStringExtra(Constants.VPN_PROFILES_SINGLE)) != null)
{
VpnProfile profile = mDataSource.getVpnProfile(id);
VpnProfile profile = mDataSource.getVpnProfile(uuid);
if (profile != null)
{ /* in case this was an edit, we remove it first */
mVpnProfiles.remove(profile);
@ -84,15 +85,15 @@ public class VpnProfileListFragment extends Fragment
mListAdapter.notifyDataSetChanged();
}
}
else if ((ids = intent.getLongArrayExtra(Constants.VPN_PROFILES_MULTIPLE)) != null)
else if ((uuids = intent.getStringArrayExtra(Constants.VPN_PROFILES_MULTIPLE)) != null)
{
for (long i : ids)
for (String id : uuids)
{
Iterator<VpnProfile> profiles = mVpnProfiles.iterator();
while (profiles.hasNext())
{
VpnProfile profile = profiles.next();
if (profile.getId() == i)
if (Objects.equals(profile.getUUID().toString(), id))
{
profiles.remove();
break;
@ -272,7 +273,7 @@ public class VpnProfileListFragment extends Fragment
int position = mSelected.iterator().next();
VpnProfile profile = (VpnProfile)mListView.getItemAtPosition(position);
Intent connectionIntent = new Intent(getActivity(), VpnProfileDetailActivity.class);
connectionIntent.putExtra(VpnProfileDataSource.KEY_ID, profile.getId());
connectionIntent.putExtra(VpnProfileDataSource.KEY_UUID, profile.getUUID().toString());
startActivity(connectionIntent);
break;
}
@ -286,11 +287,11 @@ public class VpnProfileListFragment extends Fragment
mDataSource.insertProfile(profile);
Intent intent = new Intent(Constants.VPN_PROFILES_CHANGED);
intent.putExtra(Constants.VPN_PROFILES_SINGLE, profile.getId());
intent.putExtra(Constants.VPN_PROFILES_SINGLE, profile.getUUID().toString());
LocalBroadcastManager.getInstance(getActivity()).sendBroadcast(intent);
Intent connectionIntent = new Intent(getActivity(), VpnProfileDetailActivity.class);
connectionIntent.putExtra(VpnProfileDataSource.KEY_ID, profile.getId());
connectionIntent.putExtra(VpnProfileDataSource.KEY_UUID, profile.getUUID().toString());
startActivity(connectionIntent);
break;
}
@ -301,15 +302,15 @@ public class VpnProfileListFragment extends Fragment
{
profiles.add((VpnProfile)mListView.getItemAtPosition(position));
}
long[] ids = new long[profiles.size()];
String[] uuids = new String[profiles.size()];
for (int i = 0; i < profiles.size(); i++)
{
VpnProfile profile = profiles.get(i);
ids[i] = profile.getId();
uuids[i] = profile.getUUID().toString();
mDataSource.deleteVpnProfile(profile);
}
Intent intent = new Intent(Constants.VPN_PROFILES_CHANGED);
intent.putExtra(Constants.VPN_PROFILES_MULTIPLE, ids);
intent.putExtra(Constants.VPN_PROFILES_MULTIPLE, uuids);
LocalBroadcastManager.getInstance(getActivity()).sendBroadcast(intent);
Toast.makeText(VpnProfileListFragment.this.getActivity(),
R.string.profiles_deleted, Toast.LENGTH_SHORT).show();

View File

@ -45,7 +45,7 @@ public class VpnProfileSelectActivity extends AppCompatActivity implements OnVpn
public void onVpnProfileSelected(VpnProfile profile)
{
Intent shortcut = new Intent(VpnProfileControlActivity.START_PROFILE);
shortcut.putExtra(VpnProfileControlActivity.EXTRA_VPN_PROFILE_ID, profile.getUUID().toString());
shortcut.putExtra(VpnProfileControlActivity.EXTRA_VPN_PROFILE_UUID, profile.getUUID().toString());
ShortcutInfoCompat.Builder builder = new ShortcutInfoCompat.Builder(this, profile.getUUID().toString());
builder.setIntent(shortcut);

View File

@ -140,7 +140,7 @@ public class VpnTileService extends TileService implements VpnStateService.VpnSt
}
else if (mDataSource != null)
{ /* always get the plain profile without cached password */
profile = mDataSource.getVpnProfile(profile.getId());
profile = mDataSource.getVpnProfile(profile.getUUID());
}
/* reconnect the profile in case of an error */
if (mService.getErrorState() == VpnStateService.ErrorState.NO_ERROR)
@ -173,7 +173,7 @@ public class VpnTileService extends TileService implements VpnStateService.VpnSt
Intent intent = new Intent(this, VpnProfileControlActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setAction(VpnProfileControlActivity.START_PROFILE);
intent.putExtra(VpnProfileControlActivity.EXTRA_VPN_PROFILE_ID, profile.getUUID().toString());
intent.putExtra(VpnProfileControlActivity.EXTRA_VPN_PROFILE_UUID, profile.getUUID().toString());
if (profile.getVpnType().has(VpnType.VpnTypeFeature.USER_PASS) &&
profile.getPassword() == null)
{ /* the user will have to enter the password, so collapse the drawer */