mirror of
https://github.com/moparisthebest/k-9
synced 2024-11-23 18:02:15 -05:00
Added input validation for identity settings
This commit is contained in:
parent
060d21db3e
commit
f21e14afc7
@ -22,12 +22,10 @@ import java.util.ArrayList;
|
|||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import java.util.Set;
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
@ -63,15 +61,6 @@ public class Account implements BaseAccount {
|
|||||||
public static final String IDENTITY_EMAIL_KEY = "email";
|
public static final String IDENTITY_EMAIL_KEY = "email";
|
||||||
public static final String IDENTITY_DESCRIPTION_KEY = "description";
|
public static final String IDENTITY_DESCRIPTION_KEY = "description";
|
||||||
|
|
||||||
public static final Set<String> IDENTITY_KEYS = new HashSet<String>();
|
|
||||||
static {
|
|
||||||
IDENTITY_KEYS.add(IDENTITY_NAME_KEY);
|
|
||||||
IDENTITY_KEYS.add(IDENTITY_EMAIL_KEY);
|
|
||||||
IDENTITY_KEYS.add(IDENTITY_DESCRIPTION_KEY);
|
|
||||||
IDENTITY_KEYS.add("signatureUse");
|
|
||||||
IDENTITY_KEYS.add("signature");
|
|
||||||
IDENTITY_KEYS.add("replyTo");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <pre>
|
* <pre>
|
||||||
|
99
src/com/fsck/k9/preferences/IdentitySettings.java
Normal file
99
src/com/fsck/k9/preferences/IdentitySettings.java
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
package com.fsck.k9.preferences;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
|
||||||
|
import com.fsck.k9.EmailAddressValidator;
|
||||||
|
import com.fsck.k9.K9;
|
||||||
|
import com.fsck.k9.R;
|
||||||
|
import com.fsck.k9.preferences.Settings.*;
|
||||||
|
|
||||||
|
public class IdentitySettings {
|
||||||
|
public static final Map<String, SettingsDescription> SETTINGS;
|
||||||
|
|
||||||
|
static {
|
||||||
|
Map<String, SettingsDescription> s = new LinkedHashMap<String, SettingsDescription>();
|
||||||
|
|
||||||
|
s.put("signature", new SignatureSetting());
|
||||||
|
s.put("signatureUse", new BooleanSetting(true));
|
||||||
|
s.put("replyTo", new OptionalEmailAddressSetting());
|
||||||
|
|
||||||
|
SETTINGS = Collections.unmodifiableMap(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Map<String, String> validate(Map<String, String> importedSettings,
|
||||||
|
boolean useDefaultValues) {
|
||||||
|
return Settings.validate(SETTINGS, importedSettings, useDefaultValues);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Map<String, String> getIdentitySettings(SharedPreferences storage, String uuid,
|
||||||
|
int identityIndex) {
|
||||||
|
Map<String, String> result = new HashMap<String, String>();
|
||||||
|
String prefix = uuid + ".";
|
||||||
|
String suffix = "." + Integer.toString(identityIndex);
|
||||||
|
for (String key : SETTINGS.keySet()) {
|
||||||
|
String value = storage.getString(prefix + key + suffix, null);
|
||||||
|
if (value != null) {
|
||||||
|
result.put(key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static boolean isEmailAddressValid(String email) {
|
||||||
|
return new EmailAddressValidator().isValidAddressOnly(email);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The message signature setting.
|
||||||
|
*/
|
||||||
|
public static class SignatureSetting extends SettingsDescription {
|
||||||
|
public SignatureSetting() {
|
||||||
|
super(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getDefaultValue() {
|
||||||
|
return K9.app.getResources().getString(R.string.default_signature);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object fromString(String value) throws InvalidSettingValueException {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An optional email address setting.
|
||||||
|
*/
|
||||||
|
public static class OptionalEmailAddressSetting extends SettingsDescription {
|
||||||
|
private EmailAddressValidator mValidator;
|
||||||
|
|
||||||
|
public OptionalEmailAddressSetting() {
|
||||||
|
super(null);
|
||||||
|
mValidator = new EmailAddressValidator();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object fromString(String value) throws InvalidSettingValueException {
|
||||||
|
if (value != null && !mValidator.isValidAddressOnly(value)) {
|
||||||
|
throw new InvalidSettingValueException();
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toPrettyString(Object value) {
|
||||||
|
return (value == null) ? "" : value.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object fromPrettyString(String value) throws InvalidSettingValueException {
|
||||||
|
return ("".equals(value)) ? null : fromString(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -64,7 +64,8 @@ public class Settings {
|
|||||||
|
|
||||||
if (useDefaultValue) {
|
if (useDefaultValue) {
|
||||||
Object defaultValue = desc.getDefaultValue();
|
Object defaultValue = desc.getDefaultValue();
|
||||||
validatedSettings.put(key, desc.toString(defaultValue));
|
String value = (defaultValue != null) ? desc.toString(defaultValue) : null;
|
||||||
|
validatedSettings.put(key, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -295,7 +295,7 @@ public class StorageExporter {
|
|||||||
if (comps.length >= 3) {
|
if (comps.length >= 3) {
|
||||||
String thirdPart = comps[2];
|
String thirdPart = comps[2];
|
||||||
|
|
||||||
if (Account.IDENTITY_KEYS.contains(secondPart)) {
|
if (Account.IDENTITY_DESCRIPTION_KEY.equals(secondPart)) {
|
||||||
// This is an identity key. Save identity index for later...
|
// This is an identity key. Save identity index for later...
|
||||||
try {
|
try {
|
||||||
identities.add(Integer.parseInt(thirdPart));
|
identities.add(Integer.parseInt(thirdPart));
|
||||||
@ -362,48 +362,62 @@ public class StorageExporter {
|
|||||||
|
|
||||||
serializer.startTag(null, IDENTITY_ELEMENT);
|
serializer.startTag(null, IDENTITY_ELEMENT);
|
||||||
|
|
||||||
String name = (String) prefs.get(accountUuid + "." + Account.IDENTITY_NAME_KEY +
|
String prefix = accountUuid + ".";
|
||||||
"." + identity);
|
String suffix = "." + identity;
|
||||||
|
|
||||||
|
// Write name belonging to the identity
|
||||||
|
String name = (String) prefs.get(prefix + Account.IDENTITY_NAME_KEY + suffix);
|
||||||
serializer.startTag(null, NAME_ELEMENT);
|
serializer.startTag(null, NAME_ELEMENT);
|
||||||
serializer.text(name);
|
serializer.text(name);
|
||||||
serializer.endTag(null, NAME_ELEMENT);
|
serializer.endTag(null, NAME_ELEMENT);
|
||||||
|
|
||||||
String email = (String) prefs.get(accountUuid + "." + Account.IDENTITY_EMAIL_KEY +
|
// Write email address belonging to the identity
|
||||||
"." + identity);
|
String email = (String) prefs.get(prefix + Account.IDENTITY_EMAIL_KEY + suffix);
|
||||||
serializer.startTag(null, EMAIL_ELEMENT);
|
serializer.startTag(null, EMAIL_ELEMENT);
|
||||||
serializer.text(email);
|
serializer.text(email);
|
||||||
serializer.endTag(null, EMAIL_ELEMENT);
|
serializer.endTag(null, EMAIL_ELEMENT);
|
||||||
|
|
||||||
String description = (String) prefs.get(accountUuid + "." +
|
// Write identity description
|
||||||
Account.IDENTITY_DESCRIPTION_KEY + "." + identity);
|
String description = (String) prefs.get(prefix + Account.IDENTITY_DESCRIPTION_KEY + suffix);
|
||||||
if (description != null) {
|
if (description != null) {
|
||||||
serializer.startTag(null, DESCRIPTION_ELEMENT);
|
serializer.startTag(null, DESCRIPTION_ELEMENT);
|
||||||
serializer.text(description);
|
serializer.text(description);
|
||||||
serializer.endTag(null, DESCRIPTION_ELEMENT);
|
serializer.endTag(null, DESCRIPTION_ELEMENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Write identity settings
|
||||||
serializer.startTag(null, SETTINGS_ELEMENT);
|
serializer.startTag(null, SETTINGS_ELEMENT);
|
||||||
for (Map.Entry<String, Object> entry : prefs.entrySet()) {
|
for (Map.Entry<String, Object> entry : prefs.entrySet()) {
|
||||||
String key = entry.getKey();
|
String key = entry.getKey();
|
||||||
String value = entry.getValue().toString();
|
String valueString = entry.getValue().toString();
|
||||||
String[] comps = key.split("\\.");
|
String[] comps = key.split("\\.");
|
||||||
if (comps.length >= 3) {
|
|
||||||
String keyUuid = comps[0];
|
if (comps.length < 3) {
|
||||||
String identityKey = comps[1];
|
|
||||||
String identityIndex = comps[2];
|
|
||||||
if (!keyUuid.equals(accountUuid) || !identityIndex.equals(identity)
|
|
||||||
|| !Account.IDENTITY_KEYS.contains(identityKey)
|
|
||||||
|| Account.IDENTITY_NAME_KEY.equals(identityKey)
|
|
||||||
|| Account.IDENTITY_EMAIL_KEY.equals(identityKey)
|
|
||||||
|| Account.IDENTITY_DESCRIPTION_KEY.equals(identityKey)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Skip non-identity config entries
|
// Skip non-identity config entries
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
writeKeyValue(serializer, comps[1], value);
|
String keyUuid = comps[0];
|
||||||
|
String identityKey = comps[1];
|
||||||
|
String identityIndex = comps[2];
|
||||||
|
if (!keyUuid.equals(accountUuid) || !identityIndex.equals(identity)) {
|
||||||
|
// Skip entries that belong to another identity
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsDescription setting = IdentitySettings.SETTINGS.get(identityKey);
|
||||||
|
if (setting != null) {
|
||||||
|
// Only write settings that have an entry in IdentitySettings.SETTINGS
|
||||||
|
try {
|
||||||
|
Object value = setting.fromString(valueString);
|
||||||
|
String outputValue = setting.toPrettyString(value);
|
||||||
|
writeKeyValue(serializer, identityKey, outputValue);
|
||||||
|
} catch (InvalidSettingValueException e) {
|
||||||
|
Log.w(K9.LOG_TAG, "Identity setting \"" + identityKey +
|
||||||
|
"\" has invalid value \"" + valueString +
|
||||||
|
"\" in preference storage. This shouldn't happen!");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
serializer.endTag(null, SETTINGS_ELEMENT);
|
serializer.endTag(null, SETTINGS_ELEMENT);
|
||||||
|
|
||||||
|
@ -28,6 +28,7 @@ import com.fsck.k9.mail.ConnectionSecurity;
|
|||||||
import com.fsck.k9.mail.ServerSettings;
|
import com.fsck.k9.mail.ServerSettings;
|
||||||
import com.fsck.k9.mail.Store;
|
import com.fsck.k9.mail.Store;
|
||||||
import com.fsck.k9.mail.Transport;
|
import com.fsck.k9.mail.Transport;
|
||||||
|
import com.fsck.k9.preferences.Settings.InvalidSettingValueException;
|
||||||
|
|
||||||
public class StorageImporter {
|
public class StorageImporter {
|
||||||
|
|
||||||
@ -277,7 +278,8 @@ public class StorageImporter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static AccountDescriptionPair importAccount(Context context,
|
private static AccountDescriptionPair importAccount(Context context,
|
||||||
SharedPreferences.Editor editor, ImportedAccount account, boolean overwrite) {
|
SharedPreferences.Editor editor, ImportedAccount account, boolean overwrite)
|
||||||
|
throws InvalidSettingValueException {
|
||||||
|
|
||||||
AccountDescription original = new AccountDescription(account.name, account.uuid);
|
AccountDescription original = new AccountDescription(account.name, account.uuid);
|
||||||
|
|
||||||
@ -352,7 +354,7 @@ public class StorageImporter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (account.identities != null) {
|
if (account.identities != null) {
|
||||||
importIdentities(editor, uuid, account, overwrite, existingAccount);
|
importIdentities(editor, uuid, account, overwrite, existingAccount, prefs);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write folder settings
|
// Write folder settings
|
||||||
@ -374,7 +376,8 @@ public class StorageImporter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void importIdentities(SharedPreferences.Editor editor, String uuid,
|
private static void importIdentities(SharedPreferences.Editor editor, String uuid,
|
||||||
ImportedAccount account, boolean overwrite, Account existingAccount) {
|
ImportedAccount account, boolean overwrite, Account existingAccount,
|
||||||
|
Preferences prefs) throws InvalidSettingValueException {
|
||||||
|
|
||||||
String accountKeyPrefix = uuid + ".";
|
String accountKeyPrefix = uuid + ".";
|
||||||
|
|
||||||
@ -391,17 +394,20 @@ public class StorageImporter {
|
|||||||
// Write identities
|
// Write identities
|
||||||
for (ImportedIdentity identity : account.identities) {
|
for (ImportedIdentity identity : account.identities) {
|
||||||
int writeIdentityIndex = nextIdentityIndex;
|
int writeIdentityIndex = nextIdentityIndex;
|
||||||
if (existingIdentities.size() > 0) {
|
boolean mergeSettings = false;
|
||||||
|
if (overwrite && existingIdentities.size() > 0) {
|
||||||
int identityIndex = findIdentity(identity, existingIdentities);
|
int identityIndex = findIdentity(identity, existingIdentities);
|
||||||
if (overwrite && identityIndex != -1) {
|
if (identityIndex != -1) {
|
||||||
writeIdentityIndex = identityIndex;
|
writeIdentityIndex = identityIndex;
|
||||||
|
mergeSettings = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (writeIdentityIndex == nextIdentityIndex) {
|
if (!mergeSettings) {
|
||||||
nextIdentityIndex++;
|
nextIdentityIndex++;
|
||||||
}
|
}
|
||||||
|
|
||||||
String identityDescription = identity.description;
|
String identityDescription = (identity.description == null) ?
|
||||||
|
"Imported" : identity.description;
|
||||||
if (isIdentityDescriptionUsed(identityDescription, existingIdentities)) {
|
if (isIdentityDescriptionUsed(identityDescription, existingIdentities)) {
|
||||||
// Identity description is already in use. So generate a new one by appending
|
// Identity description is already in use. So generate a new one by appending
|
||||||
// " (x)", where x is the first number >= 1 that results in an unused identity
|
// " (x)", where x is the first number >= 1 that results in an unused identity
|
||||||
@ -414,18 +420,45 @@ public class StorageImporter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
editor.putString(accountKeyPrefix + Account.IDENTITY_NAME_KEY + "." +
|
String identitySuffix = "." + writeIdentityIndex;
|
||||||
writeIdentityIndex, identity.name);
|
|
||||||
editor.putString(accountKeyPrefix + Account.IDENTITY_EMAIL_KEY + "." +
|
// Write name used in identity
|
||||||
writeIdentityIndex, identity.email);
|
String identityName = (identity.name == null) ? "" : identity.name;
|
||||||
editor.putString(accountKeyPrefix + Account.IDENTITY_DESCRIPTION_KEY + "." +
|
editor.putString(accountKeyPrefix + Account.IDENTITY_NAME_KEY + identitySuffix,
|
||||||
writeIdentityIndex, identityDescription);
|
identityName);
|
||||||
|
|
||||||
|
// Validate email address
|
||||||
|
if (!IdentitySettings.isEmailAddressValid(identity.email)) {
|
||||||
|
throw new InvalidSettingValueException();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write email address
|
||||||
|
editor.putString(accountKeyPrefix + Account.IDENTITY_EMAIL_KEY + identitySuffix,
|
||||||
|
identity.email);
|
||||||
|
|
||||||
|
// Write identity description
|
||||||
|
editor.putString(accountKeyPrefix + Account.IDENTITY_DESCRIPTION_KEY + identitySuffix,
|
||||||
|
identityDescription);
|
||||||
|
|
||||||
|
// Validate identity settings
|
||||||
|
Map<String, String> validatedSettings = IdentitySettings.validate(
|
||||||
|
identity.settings.settings, !mergeSettings);
|
||||||
|
|
||||||
|
// Merge identity settings if necessary
|
||||||
|
Map<String, String> writeSettings;
|
||||||
|
if (mergeSettings) {
|
||||||
|
writeSettings = new HashMap<String, String>(IdentitySettings.getIdentitySettings(
|
||||||
|
prefs.getPreferences(), uuid, writeIdentityIndex));
|
||||||
|
writeSettings.putAll(validatedSettings);
|
||||||
|
} else {
|
||||||
|
writeSettings = new HashMap<String, String>(validatedSettings);
|
||||||
|
}
|
||||||
|
|
||||||
// Write identity settings
|
// Write identity settings
|
||||||
for (Map.Entry<String, String> setting : identity.settings.settings.entrySet()) {
|
for (Map.Entry<String, String> setting : writeSettings.entrySet()) {
|
||||||
String key = setting.getKey();
|
String key = accountKeyPrefix + setting.getKey() + identitySuffix;
|
||||||
String value = setting.getValue();
|
String value = setting.getValue();
|
||||||
editor.putString(accountKeyPrefix + key + "." + writeIdentityIndex, value);
|
editor.putString(key, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user