Integrate VPN with new keystore and misc fixes.

* Changes
  + Pass intent to keystore when needed and hooks to resume from it.
  + Generate random, unique ID for profile instead of base64 from its
    name.
  + Add VPN to "Wirless controls" description.
  + Add credential storage to "Security & location" description.
  + More hints to set password and unlock dialogs in credential storage
    settings for actions that come from other processes.
  + Sort VPN profiles according to the names.
  + Replace Keystore with CertTool in L2tpIpsecEditor
This commit is contained in:
Hung-ying Tyan
2009-07-06 17:26:34 +08:00
parent eb7836f11e
commit 0a59b50014
10 changed files with 216 additions and 60 deletions

View File

@@ -24,6 +24,13 @@
android:layout_height="fill_parent" android:layout_height="fill_parent"
android:padding="15dip"> android:padding="15dip">
<TextView android:id="@+id/cstor_access_dialog_hint_from_action"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="@dimen/vpn_connect_normal_text_size"
android:text="@string/cstor_access_dialog_hint_from_action"
android:layout_marginBottom="10sp" />
<TextView android:id="@+id/cstor_error" <TextView android:id="@+id/cstor_error"
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"

View File

@@ -437,7 +437,7 @@
<!-- Main Settings screen settings title for things like Wi-Fi, bluetooth, airplane mode. This will take you to another screen with those settings. --> <!-- Main Settings screen settings title for things like Wi-Fi, bluetooth, airplane mode. This will take you to another screen with those settings. -->
<string name="radio_controls_title">Wireless controls</string> <string name="radio_controls_title">Wireless controls</string>
<!-- Main Settings screen settings summary text for the "Wireless controls" setting --> <!-- Main Settings screen settings summary text for the "Wireless controls" setting -->
<string name="radio_controls_summary">Manage Wi-Fi, Bluetooth, airplane mode, &amp; mobile networks</string> <string name="radio_controls_summary">Manage Wi-Fi, Bluetooth, airplane mode, mobile networks, &amp; VPNs</string>
<!-- mobile network settings screen, setting check box title --> <!-- mobile network settings screen, setting check box title -->
@@ -488,7 +488,7 @@
<!-- Main Settings screen setting option title for the item to take you the security and location screen --> <!-- Main Settings screen setting option title for the item to take you the security and location screen -->
<string name="security_settings_title">Security &amp; location</string> <string name="security_settings_title">Security &amp; location</string>
<!-- Main Settings screen setting option summary text for the item tot ake you to the security and location screen --> <!-- Main Settings screen setting option summary text for the item tot ake you to the security and location screen -->
<string name="security_settings_summary">Set My Location, screen unlock, SIM card lock</string> <string name="security_settings_summary">Set My Location, screen unlock, SIM card lock, credential storage lock</string>
<!-- In the security screen, the header title for settings related to Passwords--> <!-- In the security screen, the header title for settings related to Passwords-->
<string name="security_passwords_title">Passwords</string> <string name="security_passwords_title">Passwords</string>
@@ -1946,6 +1946,8 @@ found in the list of installed applications.</string>
<string name="cstor_access_summary">Allow applications to access secure certificates and other credentials</string> <string name="cstor_access_summary">Allow applications to access secure certificates and other credentials</string>
<!-- Title of dialog to enable/dislable access to credential storage --> <!-- Title of dialog to enable/dislable access to credential storage -->
<string name="cstor_access_dialog_title">Enter password</string> <string name="cstor_access_dialog_title">Enter password</string>
<!-- Description of dialog to enable/dislable access to credential storage from an action that requires the credential storage -->
<string name="cstor_access_dialog_hint_from_action">This action requires enabling the credential storage. Please enter the password to enable it.</string>
<!-- Title of preference to set storage password --> <!-- Title of preference to set storage password -->
<string name="cstor_set_passwd_title">Set password</string> <string name="cstor_set_passwd_title">Set password</string>
@@ -1977,6 +1979,8 @@ found in the list of installed applications.</string>
<string name="cstor_confirm_password">Confirm new password:</string> <string name="cstor_confirm_password">Confirm new password:</string>
<!-- Description when user set up the storage for the very first time --> <!-- Description when user set up the storage for the very first time -->
<string name="cstor_first_time_hint">You must set a password for the credential storage.</string> <string name="cstor_first_time_hint">You must set a password for the credential storage.</string>
<!-- Description when user set up the storage for the very first time from an action that requires the credential storage-->
<string name="cstor_first_time_hint_from_action">This action requires the credential storage but the storage has not been activated before. To activiate it, you must set a password for the credential storage.</string>
<string name="cstor_password_error">Please enter the correct password.</string> <string name="cstor_password_error">Please enter the correct password.</string>
<string name="cstor_password_error_reset_warning">Please enter the correct password. You have one more try to enter the correct password before the credential storage is erased.</string> <string name="cstor_password_error_reset_warning">Please enter the correct password. You have one more try to enter the correct password before the credential storage is erased.</string>
<string name="cstor_password_error_reset_warning_plural">Please enter the correct password. You have %d more tries to enter the correct password before the credential storage is erased.</string> <string name="cstor_password_error_reset_warning_plural">Please enter the correct password. You have %d more tries to enter the correct password before the credential storage is erased.</string>

View File

@@ -577,8 +577,7 @@ public class SecuritySettings extends PreferenceActivity implements
: R.string.cstor_password_error); : R.string.cstor_password_error);
if (count <= 3) { if (count <= 3) {
if (count == 1) { if (count == 1) {
v.setText(getString( v.setText(R.string.cstor_password_error_reset_warning);
R.string.cstor_password_error_reset_warning));
} else { } else {
String format = getString( String format = getString(
R.string.cstor_password_error_reset_warning_plural); R.string.cstor_password_error_reset_warning_plural);
@@ -691,11 +690,15 @@ public class SecuritySettings extends PreferenceActivity implements
return v; return v;
} }
private void hideError() { private void hide(int viewId) {
View v = mView.findViewById(R.id.cstor_error); View v = mView.findViewById(viewId);
if (v != null) v.setVisibility(View.GONE); if (v != null) v.setVisibility(View.GONE);
} }
private void hideError() {
hide(R.id.cstor_error);
}
private String getText(int viewId) { private String getText(int viewId) {
return ((TextView) mView.findViewById(viewId)).getText().toString(); return ((TextView) mView.findViewById(viewId)).getText().toString();
} }
@@ -705,6 +708,11 @@ public class SecuritySettings extends PreferenceActivity implements
if (v != null) v.setText(text); if (v != null) v.setText(text);
} }
private void setText(int viewId, int textId) {
TextView v = (TextView) mView.findViewById(viewId);
if (v != null) v.setText(textId);
}
private void enablePreferences(boolean enabled) { private void enablePreferences(boolean enabled) {
mAccessCheckBox.setEnabled(enabled); mAccessCheckBox.setEnabled(enabled);
mResetButton.setEnabled(enabled); mResetButton.setEnabled(enabled);
@@ -773,6 +781,12 @@ public class SecuritySettings extends PreferenceActivity implements
R.layout.cstor_unlock_dialog_view, null); R.layout.cstor_unlock_dialog_view, null);
hideError(); hideError();
// show extra hint only when the action comes from outside
if ((mSpecialIntent == null)
&& (mCstorAddCredentialHelper == null)) {
hide(R.id.cstor_access_dialog_hint_from_action);
}
Dialog d = new AlertDialog.Builder(SecuritySettings.this) Dialog d = new AlertDialog.Builder(SecuritySettings.this)
.setView(mView) .setView(mView)
.setTitle(R.string.cstor_access_dialog_title) .setTitle(R.string.cstor_access_dialog_title)
@@ -790,6 +804,13 @@ public class SecuritySettings extends PreferenceActivity implements
R.layout.cstor_set_password_dialog_view, null); R.layout.cstor_set_password_dialog_view, null);
hideError(); hideError();
// show extra hint only when the action comes from outside
if ((mSpecialIntent != null)
|| (mCstorAddCredentialHelper != null)) {
setText(R.id.cstor_first_time_hint,
R.string.cstor_first_time_hint_from_action);
}
switch (id) { switch (id) {
case CSTOR_INIT_DIALOG: case CSTOR_INIT_DIALOG:
mView.findViewById(R.id.cstor_old_password_block) mView.findViewById(R.id.cstor_old_password_block)
@@ -835,9 +856,9 @@ public class SecuritySettings extends PreferenceActivity implements
hideError(); hideError();
setText(R.id.cstor_credential_name_title, setText(R.id.cstor_credential_name_title,
getString(R.string.cstor_credential_name)); R.string.cstor_credential_name);
setText(R.id.cstor_credential_info_title, setText(R.id.cstor_credential_info_title,
getString(R.string.cstor_credential_info)); R.string.cstor_credential_info);
setText(R.id.cstor_credential_info, setText(R.id.cstor_credential_info,
mCstorAddCredentialHelper.getDescription().toString()); mCstorAddCredentialHelper.getDescription().toString());

View File

@@ -60,12 +60,6 @@ class L2tpEditor extends VpnProfileEditor {
: validate(mSecretString, R.string.vpn_l2tp_secret)); : validate(mSecretString, R.string.vpn_l2tp_secret));
} }
@Override
public void saveSecrets(String originalProfileName) {
L2tpProfile profile = (L2tpProfile) getProfile();
// TODO: fill up the implementation after keystore is available
}
private Preference createSecretPreference(Context c) { private Preference createSecretPreference(Context c) {
final L2tpProfile profile = (L2tpProfile) getProfile(); final L2tpProfile profile = (L2tpProfile) getProfile();
CheckBoxPreference secret = mSecret = new CheckBoxPreference(c); CheckBoxPreference secret = mSecret = new CheckBoxPreference(c);

View File

@@ -24,7 +24,7 @@ import android.preference.EditTextPreference;
import android.preference.ListPreference; import android.preference.ListPreference;
import android.preference.Preference; import android.preference.Preference;
import android.preference.PreferenceGroup; import android.preference.PreferenceGroup;
import android.security.Keystore; import android.security.CertTool;
import android.text.TextUtils; import android.text.TextUtils;
/** /**
@@ -67,7 +67,7 @@ class L2tpIpsecEditor extends L2tpEditor {
mUserCertificate = createListPreference(c, mUserCertificate = createListPreference(c,
R.string.vpn_user_certificate_title, R.string.vpn_user_certificate_title,
mProfile.getUserCertificate(), mProfile.getUserCertificate(),
Keystore.getInstance().getAllUserCertificateKeys(), CertTool.getInstance().getAllUserCertificateKeys(),
new Preference.OnPreferenceChangeListener() { new Preference.OnPreferenceChangeListener() {
public boolean onPreferenceChange( public boolean onPreferenceChange(
Preference pref, Object newValue) { Preference pref, Object newValue) {
@@ -86,7 +86,7 @@ class L2tpIpsecEditor extends L2tpEditor {
mCaCertificate = createListPreference(c, mCaCertificate = createListPreference(c,
R.string.vpn_ca_certificate_title, R.string.vpn_ca_certificate_title,
mProfile.getCaCertificate(), mProfile.getCaCertificate(),
Keystore.getInstance().getAllCaCertificateKeys(), CertTool.getInstance().getAllCaCertificateKeys(),
new Preference.OnPreferenceChangeListener() { new Preference.OnPreferenceChangeListener() {
public boolean onPreferenceChange( public boolean onPreferenceChange(
Preference pref, Object newValue) { Preference pref, Object newValue) {

View File

@@ -50,13 +50,6 @@ class L2tpIpsecPskEditor extends L2tpEditor {
: validate(mPresharedKey, R.string.vpn_ipsec_presharedkey)); : validate(mPresharedKey, R.string.vpn_ipsec_presharedkey));
} }
@Override
public void saveSecrets(String originalProfileName) {
L2tpIpsecPskProfile profile = (L2tpIpsecPskProfile) getProfile();
profile.getPresharedKey();
// TODO: fill up the implementation after keystore is available
}
private Preference createPresharedKeyPreference(Context c) { private Preference createPresharedKeyPreference(Context c) {
final L2tpIpsecPskProfile profile = (L2tpIpsecPskProfile) getProfile(); final L2tpIpsecPskProfile profile = (L2tpIpsecPskProfile) getProfile();
mPresharedKey = createSecretPreference(c, mPresharedKey = createSecretPreference(c,

View File

@@ -23,8 +23,6 @@ import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.widget.Toast; import android.widget.Toast;
import org.apache.commons.codec.binary.Base64;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileOutputStream; import java.io.FileOutputStream;
@@ -59,10 +57,6 @@ class Util {
createErrorDialog(c, message, listener).show(); createErrorDialog(c, message, listener).show();
} }
static String base64Encode(byte[] bytes) {
return new String(Base64.encodeBase64(bytes));
}
static void deleteFile(String path) { static void deleteFile(String path) {
deleteFile(new File(path)); deleteFile(new File(path));
} }

View File

@@ -46,7 +46,6 @@ public class VpnEditor extends PreferenceActivity {
private VpnProfileEditor mProfileEditor; private VpnProfileEditor mProfileEditor;
private boolean mAddingProfile; private boolean mAddingProfile;
private String mOriginalProfileName;
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
@@ -54,9 +53,6 @@ public class VpnEditor extends PreferenceActivity {
VpnProfile p = (VpnProfile) ((savedInstanceState == null) VpnProfile p = (VpnProfile) ((savedInstanceState == null)
? getIntent().getParcelableExtra(VpnSettings.KEY_VPN_PROFILE) ? getIntent().getParcelableExtra(VpnSettings.KEY_VPN_PROFILE)
: savedInstanceState.getParcelable(KEY_PROFILE)); : savedInstanceState.getParcelable(KEY_PROFILE));
mOriginalProfileName = (savedInstanceState == null)
? p.getName()
: savedInstanceState.getString(KEY_ORIGINAL_PROFILE_NAME);
mProfileEditor = getEditor(p); mProfileEditor = getEditor(p);
mAddingProfile = TextUtils.isEmpty(p.getName()); mAddingProfile = TextUtils.isEmpty(p.getName());
@@ -71,7 +67,6 @@ public class VpnEditor extends PreferenceActivity {
if (mProfileEditor == null) return; if (mProfileEditor == null) return;
outState.putParcelable(KEY_PROFILE, getProfile()); outState.putParcelable(KEY_PROFILE, getProfile());
outState.putString(KEY_ORIGINAL_PROFILE_NAME, mOriginalProfileName);
} }
@Override @Override
@@ -126,13 +121,11 @@ public class VpnEditor extends PreferenceActivity {
return false; return false;
} }
mProfileEditor.saveSecrets(mOriginalProfileName);
setResult(getProfile()); setResult(getProfile());
return true; return true;
} }
private void setResult(VpnProfile p) { private void setResult(VpnProfile p) {
p.setId(Util.base64Encode(p.getName().getBytes()));
Intent intent = new Intent(this, VpnSettings.class); Intent intent = new Intent(this, VpnSettings.class);
intent.putExtra(VpnSettings.KEY_VPN_PROFILE, (Parcelable) p); intent.putExtra(VpnSettings.KEY_VPN_PROFILE, (Parcelable) p);
setResult(RESULT_OK, intent); setResult(RESULT_OK, intent);

View File

@@ -91,13 +91,6 @@ class VpnProfileEditor {
: validate(mServerName, R.string.vpn_vpn_server)); : validate(mServerName, R.string.vpn_vpn_server));
} }
/**
* Saves the secrets in this profile.
* @param originalProfileName the original profile name
*/
public void saveSecrets(String originalProfileName) {
}
/** /**
* Creates a preference for users to input domain suffices. * Creates a preference for users to input domain suffices.
*/ */

View File

@@ -17,6 +17,7 @@
package com.android.settings.vpn; package com.android.settings.vpn;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.SecuritySettings;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.app.Dialog; import android.app.Dialog;
@@ -24,6 +25,8 @@ import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.net.vpn.L2tpIpsecPskProfile;
import android.net.vpn.L2tpProfile;
import android.net.vpn.VpnManager; import android.net.vpn.VpnManager;
import android.net.vpn.VpnProfile; import android.net.vpn.VpnProfile;
import android.net.vpn.VpnState; import android.net.vpn.VpnState;
@@ -38,6 +41,7 @@ import android.preference.PreferenceCategory;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.preference.PreferenceScreen; import android.preference.PreferenceScreen;
import android.preference.Preference.OnPreferenceClickListener; import android.preference.Preference.OnPreferenceClickListener;
import android.security.Keystore;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import android.view.ContextMenu; import android.view.ContextMenu;
@@ -54,8 +58,8 @@ import java.io.IOException;
import java.io.ObjectInputStream; import java.io.ObjectInputStream;
import java.io.ObjectOutputStream; import java.io.ObjectOutputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
@@ -113,6 +117,9 @@ public class VpnSettings extends PreferenceActivity implements
private VpnProfileActor mConnectingActor; private VpnProfileActor mConnectingActor;
private boolean mStateSaved = false; private boolean mStateSaved = false;
// states saved for unlocking keystore
private Runnable mUnlockAction;
private VpnManager mVpnManager = new VpnManager(this); private VpnManager mVpnManager = new VpnManager(this);
private ConnectivityReceiver mConnectivityReceiver = private ConnectivityReceiver mConnectivityReceiver =
@@ -169,6 +176,12 @@ public class VpnSettings extends PreferenceActivity implements
public void onResume() { public void onResume() {
super.onResume(); super.onResume();
mStatusChecker.onResume(); mStatusChecker.onResume();
if ((mUnlockAction != null) && isKeystoreUnlocked()) {
Runnable action = mUnlockAction;
mUnlockAction = null;
runOnUiThread(action);
}
} }
@Override @Override
@@ -279,9 +292,9 @@ public class VpnSettings extends PreferenceActivity implements
} }
@Override @Override
protected void onActivityResult(int requestCode, int resultCode, protected void onActivityResult(final int requestCode, final int resultCode,
Intent data) { final Intent data) {
int index = mIndexOfEditedProfile; final int index = mIndexOfEditedProfile;
mIndexOfEditedProfile = -1; mIndexOfEditedProfile = -1;
if ((resultCode == RESULT_CANCELED) || (data == null)) { if ((resultCode == RESULT_CANCELED) || (data == null)) {
@@ -312,6 +325,16 @@ public class VpnSettings extends PreferenceActivity implements
return; return;
} }
if (needKeystoreToSave(p)) {
Runnable action = new Runnable() {
public void run() {
mIndexOfEditedProfile = index;
onActivityResult(requestCode, resultCode, data);
}
};
if (!unlockKeystore(p, action)) return;
}
try { try {
if ((index < 0) || (index >= mVpnProfileList.size())) { if ((index < 0) || (index >= mVpnProfileList.size())) {
addProfile(p); addProfile(p);
@@ -414,7 +437,27 @@ public class VpnSettings extends PreferenceActivity implements
.show(); .show();
} }
// Randomly generates an ID for the profile.
// The ID is unique and only set once when the profile is created.
private void setProfileId(VpnProfile profile) {
String id;
while (true) {
id = String.valueOf(Math.abs(
Double.doubleToLongBits(Math.random())));
if (id.length() >= 8) break;
}
for (VpnProfile p : mVpnProfileList) {
if (p.getId().equals(id)) {
setProfileId(profile);
return;
}
}
profile.setId(id);
}
private void addProfile(VpnProfile p) throws IOException { private void addProfile(VpnProfile p) throws IOException {
setProfileId(p);
saveProfileToStorage(p); saveProfileToStorage(p);
mVpnProfileList.add(p); mVpnProfileList.add(p);
addPreferenceFor(p); addPreferenceFor(p);
@@ -445,8 +488,11 @@ public class VpnSettings extends PreferenceActivity implements
throw new RuntimeException("inconsistent state!"); throw new RuntimeException("inconsistent state!");
} }
// TODO: call saveSecret(String) after keystore is available p.setId(oldProfile.getId());
processSecrets(p);
// TODO: remove copyFiles once the setId() code propagates.
// Copy config files and remove the old ones if they are in different // Copy config files and remove the old ones if they are in different
// directories. // directories.
if (Util.copyFiles(getProfileDir(oldProfile), getProfileDir(p))) { if (Util.copyFiles(getProfileDir(oldProfile), getProfileDir(p))) {
@@ -463,25 +509,93 @@ public class VpnSettings extends PreferenceActivity implements
startActivityForResult(intent, REQUEST_SELECT_VPN_TYPE); startActivityForResult(intent, REQUEST_SELECT_VPN_TYPE);
} }
private void startVpnEditor(VpnProfile profile) { private boolean isKeystoreUnlocked() {
return (Keystore.getInstance().getState() == Keystore.UNLOCKED);
}
// Returns true if the profile needs to access keystore
private boolean needKeystoreToSave(VpnProfile p) {
return needKeystoreToConnect(p);
}
// Returns true if the profile needs to access keystore
private boolean needKeystoreToEdit(VpnProfile p) {
switch (p.getType()) {
case L2TP_IPSEC:
case L2TP_IPSEC_PSK:
return true;
default:
return false;
}
}
// Returns true if the profile needs to access keystore
private boolean needKeystoreToConnect(VpnProfile p) {
switch (p.getType()) {
case L2TP_IPSEC:
case L2TP_IPSEC_PSK:
return true;
case L2TP:
return ((L2tpProfile) p).isSecretEnabled();
default:
return false;
}
}
// Returns true if keystore is unlocked or keystore is not a concern
private boolean unlockKeystore(VpnProfile p, Runnable action) {
if (isKeystoreUnlocked()) return true;
mUnlockAction = action;
startActivity(
new Intent(SecuritySettings.ACTION_UNLOCK_CREDENTIAL_STORAGE));
return false;
}
private void startVpnEditor(final VpnProfile profile) {
if (needKeystoreToEdit(profile)) {
Runnable action = new Runnable() {
public void run() {
startVpnEditor(profile);
}
};
if (!unlockKeystore(profile, action)) return;
}
Intent intent = new Intent(this, VpnEditor.class); Intent intent = new Intent(this, VpnEditor.class);
intent.putExtra(KEY_VPN_PROFILE, (Parcelable) profile); intent.putExtra(KEY_VPN_PROFILE, (Parcelable) profile);
startActivityForResult(intent, REQUEST_ADD_OR_EDIT_PROFILE); startActivityForResult(intent, REQUEST_ADD_OR_EDIT_PROFILE);
} }
private synchronized void connect(final VpnProfile p) {
if (needKeystoreToConnect(p)) {
Runnable action = new Runnable() {
public void run() {
connect(p);
}
};
if (!unlockKeystore(p, action)) return;
}
mConnectingActor = getActor(p);
if (mConnectingActor.isConnectDialogNeeded()) {
removeDialog(DIALOG_CONNECT);
showDialog(DIALOG_CONNECT);
} else {
changeState(p, VpnState.CONNECTING);
mConnectingActor.connect(null);
}
}
// Do connect or disconnect based on the current state. // Do connect or disconnect based on the current state.
private synchronized void connectOrDisconnect(VpnProfile p) { private synchronized void connectOrDisconnect(VpnProfile p) {
VpnPreference pref = mVpnPreferenceMap.get(p.getName()); VpnPreference pref = mVpnPreferenceMap.get(p.getName());
switch (p.getState()) { switch (p.getState()) {
case IDLE: case IDLE:
mConnectingActor = getActor(p); connect(p);
if (mConnectingActor.isConnectDialogNeeded()) {
removeDialog(DIALOG_CONNECT);
showDialog(DIALOG_CONNECT);
} else {
changeState(p, VpnState.CONNECTING);
mConnectingActor.connect(null);
}
break; break;
case CONNECTING: case CONNECTING:
@@ -601,7 +715,6 @@ public class VpnSettings extends PreferenceActivity implements
File root = new File(PROFILES_ROOT); File root = new File(PROFILES_ROOT);
String[] dirs = root.list(); String[] dirs = root.list();
if (dirs == null) return; if (dirs == null) return;
Arrays.sort(dirs);
for (String dir : dirs) { for (String dir : dirs) {
File f = new File(new File(root, dir), PROFILE_OBJ_FILE); File f = new File(new File(root, dir), PROFILE_OBJ_FILE);
if (!f.exists()) continue; if (!f.exists()) continue;
@@ -611,11 +724,21 @@ public class VpnSettings extends PreferenceActivity implements
if (!checkIdConsistency(dir, p)) continue; if (!checkIdConsistency(dir, p)) continue;
mVpnProfileList.add(p); mVpnProfileList.add(p);
addPreferenceFor(p);
} catch (IOException e) { } catch (IOException e) {
Log.e(TAG, "retrieveVpnListFromStorage()", e); Log.e(TAG, "retrieveVpnListFromStorage()", e);
} }
} }
Collections.sort(mVpnProfileList, new Comparator<VpnProfile>() {
public int compare(VpnProfile p1, VpnProfile p2) {
return p1.getName().compareTo(p2.getName());
}
public boolean equals(VpnProfile p) {
// not used
return false;
}
});
for (VpnProfile p : mVpnProfileList) addPreferenceFor(p);
disableProfilePreferencesIfOneActive(); disableProfilePreferencesIfOneActive();
} }
@@ -668,6 +791,40 @@ public class VpnSettings extends PreferenceActivity implements
return mVpnManager.createVpnProfile(Enum.valueOf(VpnType.class, type)); return mVpnManager.createVpnProfile(Enum.valueOf(VpnType.class, type));
} }
private static final String NAMESPACE_VPN = "vpn";
private static final String KEY_PREFIX_IPSEC_PSK = "ipsk000";
private static final String KEY_PREFIX_L2TP_SECRET = "lscrt000";
private void processSecrets(VpnProfile p) {
Keystore ks = Keystore.getInstance();
switch (p.getType()) {
case L2TP_IPSEC_PSK:
L2tpIpsecPskProfile pskProfile = (L2tpIpsecPskProfile) p;
String keyName = KEY_PREFIX_IPSEC_PSK + p.getId();
String presharedKey = pskProfile.getPresharedKey();
if (!presharedKey.equals(keyName)) {
ks.put(NAMESPACE_VPN, keyName, presharedKey);
pskProfile.setPresharedKey(NAMESPACE_VPN + "_" + keyName);
}
// pass through
case L2TP:
L2tpProfile l2tpProfile = (L2tpProfile) p;
keyName = KEY_PREFIX_L2TP_SECRET + p.getId();
String secret = l2tpProfile.getSecretString();
if (l2tpProfile.isSecretEnabled()) {
if (!secret.equals(keyName)) {
ks.put(NAMESPACE_VPN, keyName, secret);
l2tpProfile.setSecretString(
NAMESPACE_VPN + "_" + keyName);
}
} else {
ks.remove(NAMESPACE_VPN, keyName);
}
break;
}
}
private class VpnPreference extends Preference { private class VpnPreference extends Preference {
VpnProfile mProfile; VpnProfile mProfile;
VpnPreference(Context c, VpnProfile p) { VpnPreference(Context c, VpnProfile p) {