mirror of https://github.com/M66B/FairEmail.git
Show warning for control/whitespace chars in passwords
This commit is contained in:
parent
b696b637e7
commit
4fa7c48d2b
|
@ -30,7 +30,9 @@ import android.net.Uri;
|
|||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.text.Editable;
|
||||
import android.text.TextUtils;
|
||||
import android.text.TextWatcher;
|
||||
import android.text.method.LinkMovementMethod;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
|
@ -88,6 +90,7 @@ public class FragmentAccount extends FragmentBase {
|
|||
private EditText etPort;
|
||||
private EditText etUser;
|
||||
private TextInputLayout tilPassword;
|
||||
private TextView tvCharacters;
|
||||
private Button btnOAuth;
|
||||
private TextView tvOAuthSupport;
|
||||
private EditText etRealm;
|
||||
|
@ -195,6 +198,7 @@ public class FragmentAccount extends FragmentBase {
|
|||
cbInsecure = view.findViewById(R.id.cbInsecure);
|
||||
etUser = view.findViewById(R.id.etUser);
|
||||
tilPassword = view.findViewById(R.id.tilPassword);
|
||||
tvCharacters = view.findViewById(R.id.tvCharacters);
|
||||
btnOAuth = view.findViewById(R.id.btnOAuth);
|
||||
tvOAuthSupport = view.findViewById(R.id.tvOAuthSupport);
|
||||
etRealm = view.findViewById(R.id.etRealm);
|
||||
|
@ -310,6 +314,28 @@ public class FragmentAccount extends FragmentBase {
|
|||
}
|
||||
});
|
||||
|
||||
tilPassword.getEditText().addTextChangedListener(new TextWatcher() {
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable s) {
|
||||
String password = s.toString();
|
||||
boolean warning = (Helper.containsWhiteSpace(password) ||
|
||||
Helper.containsControlChars(password));
|
||||
tvCharacters.setVisibility(warning &&
|
||||
tilPassword.getVisibility() == View.VISIBLE
|
||||
? View.VISIBLE : View.GONE);
|
||||
}
|
||||
});
|
||||
|
||||
btnOAuth.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
|
@ -436,6 +462,7 @@ public class FragmentAccount extends FragmentBase {
|
|||
|
||||
rgEncryption.setVisibility(View.GONE);
|
||||
cbInsecure.setVisibility(View.GONE);
|
||||
tvCharacters.setVisibility(View.GONE);
|
||||
|
||||
btnAdvanced.setVisibility(View.GONE);
|
||||
|
||||
|
|
|
@ -99,6 +99,7 @@ public class FragmentIdentity extends FragmentBase {
|
|||
private EditText etPort;
|
||||
private EditText etUser;
|
||||
private TextInputLayout tilPassword;
|
||||
private TextView tvCharacters;
|
||||
private Button btnOAuth;
|
||||
private EditText etRealm;
|
||||
private CheckBox cbUseIp;
|
||||
|
@ -183,6 +184,7 @@ public class FragmentIdentity extends FragmentBase {
|
|||
etPort = view.findViewById(R.id.etPort);
|
||||
etUser = view.findViewById(R.id.etUser);
|
||||
tilPassword = view.findViewById(R.id.tilPassword);
|
||||
tvCharacters = view.findViewById(R.id.tvCharacters);
|
||||
btnOAuth = view.findViewById(R.id.btnOAuth);
|
||||
etRealm = view.findViewById(R.id.etRealm);
|
||||
cbUseIp = view.findViewById(R.id.cbUseIp);
|
||||
|
@ -292,6 +294,23 @@ public class FragmentIdentity extends FragmentBase {
|
|||
}
|
||||
});
|
||||
|
||||
tilPassword.getEditText().addTextChangedListener(new TextWatcher() {
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable s) {
|
||||
checkPassword(s.toString());
|
||||
}
|
||||
});
|
||||
|
||||
btnColor.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
|
@ -347,6 +366,7 @@ public class FragmentIdentity extends FragmentBase {
|
|||
public void onClick(View v) {
|
||||
int visibility = (grpAdvanced.getVisibility() == View.VISIBLE ? View.GONE : View.VISIBLE);
|
||||
grpAdvanced.setVisibility(visibility);
|
||||
checkPassword(tilPassword.getEditText().getText().toString());
|
||||
if (visibility == View.VISIBLE)
|
||||
new Handler().post(new Runnable() {
|
||||
@Override
|
||||
|
@ -452,6 +472,7 @@ public class FragmentIdentity extends FragmentBase {
|
|||
btnAutoConfig.setEnabled(false);
|
||||
pbAutoConfig.setVisibility(View.GONE);
|
||||
cbInsecure.setVisibility(View.GONE);
|
||||
tvCharacters.setVisibility(View.GONE);
|
||||
|
||||
btnAdvanced.setVisibility(View.GONE);
|
||||
|
||||
|
@ -515,6 +536,15 @@ public class FragmentIdentity extends FragmentBase {
|
|||
}.execute(this, args, "identity:config");
|
||||
}
|
||||
|
||||
private void checkPassword(String password) {
|
||||
boolean warning = (Helper.containsWhiteSpace(password) ||
|
||||
Helper.containsControlChars(password));
|
||||
tvCharacters.setVisibility(warning &&
|
||||
grpAdvanced.getVisibility() == View.VISIBLE
|
||||
? View.VISIBLE : View.GONE);
|
||||
|
||||
}
|
||||
|
||||
private void onSave(boolean should) {
|
||||
EntityAccount account = (EntityAccount) spAccount.getSelectedItem();
|
||||
|
||||
|
|
|
@ -26,7 +26,9 @@ import android.graphics.Color;
|
|||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.text.Editable;
|
||||
import android.text.TextUtils;
|
||||
import android.text.TextWatcher;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
|
@ -64,6 +66,7 @@ public class FragmentPop extends FragmentBase {
|
|||
private EditText etPort;
|
||||
private EditText etUser;
|
||||
private TextInputLayout tilPassword;
|
||||
private TextView tvCharacters;
|
||||
|
||||
private EditText etName;
|
||||
private ViewButtonColor btnColor;
|
||||
|
@ -113,6 +116,7 @@ public class FragmentPop extends FragmentBase {
|
|||
cbInsecure = view.findViewById(R.id.cbInsecure);
|
||||
etUser = view.findViewById(R.id.etUser);
|
||||
tilPassword = view.findViewById(R.id.tilPassword);
|
||||
tvCharacters = view.findViewById(R.id.tvCharacters);
|
||||
|
||||
etName = view.findViewById(R.id.etName);
|
||||
btnColor = view.findViewById(R.id.btnColor);
|
||||
|
@ -132,6 +136,28 @@ public class FragmentPop extends FragmentBase {
|
|||
|
||||
pbWait = view.findViewById(R.id.pbWait);
|
||||
|
||||
tilPassword.getEditText().addTextChangedListener(new TextWatcher() {
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable s) {
|
||||
String password = s.toString();
|
||||
boolean warning = (Helper.containsWhiteSpace(password) ||
|
||||
Helper.containsControlChars(password));
|
||||
tvCharacters.setVisibility(warning &&
|
||||
tilPassword.getVisibility() == View.VISIBLE
|
||||
? View.VISIBLE : View.GONE);
|
||||
}
|
||||
});
|
||||
|
||||
btnColor.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
|
@ -169,6 +195,7 @@ public class FragmentPop extends FragmentBase {
|
|||
// Initialize
|
||||
Helper.setViewsEnabled(view, false);
|
||||
|
||||
tvCharacters.setVisibility(View.GONE);
|
||||
pbSave.setVisibility(View.GONE);
|
||||
grpError.setVisibility(View.GONE);
|
||||
|
||||
|
|
|
@ -24,7 +24,9 @@ import android.content.Intent;
|
|||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.text.Editable;
|
||||
import android.text.TextUtils;
|
||||
import android.text.TextWatcher;
|
||||
import android.text.method.LinkMovementMethod;
|
||||
import android.util.Patterns;
|
||||
import android.view.KeyEvent;
|
||||
|
@ -59,6 +61,7 @@ public class FragmentQuickSetup extends FragmentBase {
|
|||
private EditText etName;
|
||||
private EditText etEmail;
|
||||
private TextInputLayout tilPassword;
|
||||
private TextView tvCharacters;
|
||||
private Button btnCheck;
|
||||
private ContentLoadingProgressBar pbCheck;
|
||||
|
||||
|
@ -88,6 +91,7 @@ public class FragmentQuickSetup extends FragmentBase {
|
|||
etName = view.findViewById(R.id.etName);
|
||||
etEmail = view.findViewById(R.id.etEmail);
|
||||
tilPassword = view.findViewById(R.id.tilPassword);
|
||||
tvCharacters = view.findViewById(R.id.tvCharacters);
|
||||
btnCheck = view.findViewById(R.id.btnCheck);
|
||||
pbCheck = view.findViewById(R.id.pbCheck);
|
||||
|
||||
|
@ -119,6 +123,28 @@ public class FragmentQuickSetup extends FragmentBase {
|
|||
}
|
||||
});
|
||||
|
||||
tilPassword.getEditText().addTextChangedListener(new TextWatcher() {
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable s) {
|
||||
String password = s.toString();
|
||||
boolean warning = (Helper.containsWhiteSpace(password) ||
|
||||
Helper.containsControlChars(password));
|
||||
tvCharacters.setVisibility(warning &&
|
||||
tilPassword.getVisibility() == View.VISIBLE
|
||||
? View.VISIBLE : View.GONE);
|
||||
}
|
||||
});
|
||||
|
||||
btnCheck.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
|
@ -149,6 +175,7 @@ public class FragmentQuickSetup extends FragmentBase {
|
|||
});
|
||||
|
||||
// Initialize
|
||||
tvCharacters.setVisibility(View.GONE);
|
||||
pbCheck.setVisibility(View.GONE);
|
||||
pbSave.setVisibility(View.GONE);
|
||||
btnHelp.setVisibility(View.GONE);
|
||||
|
|
|
@ -584,6 +584,26 @@ public class Helper {
|
|||
return result.toArray(new String[0]);
|
||||
}
|
||||
|
||||
static boolean containsWhiteSpace(String text) {
|
||||
return text.matches(".*\\s+.*");
|
||||
}
|
||||
|
||||
static boolean containsControlChars(String text) {
|
||||
for (int offset = 0; offset < text.length(); ) {
|
||||
int codePoint = text.codePointAt(offset);
|
||||
offset += Character.charCount(codePoint);
|
||||
switch (Character.getType(codePoint)) {
|
||||
case Character.CONTROL: // \p{Cc}
|
||||
case Character.FORMAT: // \p{Cf}
|
||||
case Character.PRIVATE_USE: // \p{Co}
|
||||
case Character.SURROGATE: // \p{Cs}
|
||||
case Character.UNASSIGNED: // \p{Cn}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Files
|
||||
|
||||
static String sanitizeFilename(String name) {
|
||||
|
|
|
@ -243,6 +243,18 @@
|
|||
android:textAppearance="@style/TextAppearance.AppCompat.Medium" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvCharacters"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:autoLink="web"
|
||||
android:text="@string/title_setup_password_chars"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
android:textColor="?attr/colorWarning"
|
||||
android:textIsSelectable="true"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/tilPassword" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/btnOAuth"
|
||||
style="@style/buttonStyleSmall"
|
||||
|
@ -254,7 +266,7 @@
|
|||
android:tag="disable"
|
||||
android:text="@string/title_setup_authentication"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/tilPassword" />
|
||||
app:layout_constraintTop_toBottomOf="@id/tvCharacters" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvOAuthSupport"
|
||||
|
|
|
@ -430,6 +430,18 @@
|
|||
android:textAppearance="@style/TextAppearance.AppCompat.Medium" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvCharacters"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:autoLink="web"
|
||||
android:text="@string/title_setup_password_chars"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
android:textColor="?attr/colorWarning"
|
||||
android:textIsSelectable="true"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/tilPassword" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/btnOAuth"
|
||||
style="@style/buttonStyleSmall"
|
||||
|
@ -441,7 +453,7 @@
|
|||
android:tag="disable"
|
||||
android:text="@string/title_setup_authentication"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/tilPassword" />
|
||||
app:layout_constraintTop_toBottomOf="@id/tvCharacters" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvRealm"
|
||||
|
|
|
@ -163,6 +163,18 @@
|
|||
android:textAppearance="@style/TextAppearance.AppCompat.Medium" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvCharacters"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:autoLink="web"
|
||||
android:text="@string/title_setup_password_chars"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
android:textColor="?attr/colorWarning"
|
||||
android:textIsSelectable="true"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/tilPassword" />
|
||||
|
||||
<!-- name -->
|
||||
|
||||
<TextView
|
||||
|
@ -173,7 +185,7 @@
|
|||
android:text="@string/title_account_name"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/tilPassword" />
|
||||
app:layout_constraintTop_toBottomOf="@id/tvCharacters" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvNameRemark"
|
||||
|
|
|
@ -61,6 +61,18 @@
|
|||
android:textAppearance="@style/TextAppearance.AppCompat.Medium" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvCharacters"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:autoLink="web"
|
||||
android:text="@string/title_setup_password_chars"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
android:textColor="?attr/colorWarning"
|
||||
android:textIsSelectable="true"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/tilPassword" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvHint"
|
||||
android:layout_width="wrap_content"
|
||||
|
@ -70,7 +82,7 @@
|
|||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
android:textStyle="italic"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/tilPassword" />
|
||||
app:layout_constraintTop_toBottomOf="@id/tvCharacters" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/btnCheck"
|
||||
|
|
|
@ -182,6 +182,7 @@
|
|||
<string name="title_setup_import">Import settings</string>
|
||||
<string name="title_setup_import_do">Imported accounts will be added without overwriting any existing ones</string>
|
||||
<string name="title_setup_password">Password</string>
|
||||
<string name="title_setup_password_chars">Password contains control or whitespace characters</string>
|
||||
<string name="title_setup_password_repeat">Repeat password</string>
|
||||
<string name="title_setup_password_missing">Password missing</string>
|
||||
<string name="title_setup_password_different">Passwords don\'t match</string>
|
||||
|
|
Loading…
Reference in New Issue