Disallow importing empty secrets

Fixes #975

And display "ERROR" for any existing bad entries. This is kind of ugly,
but it's better than crashing, and there are probably very few (or zero)
users who have bad entries anyway.
This commit is contained in:
Alexander Bakker 2022-09-17 17:30:14 +02:00
parent 66b7fd38d6
commit 3bc10bd4b8
14 changed files with 159 additions and 24 deletions

View file

@ -59,6 +59,9 @@ public class GoogleAuthInfo implements Transferable, Serializable {
} catch (EncodingException e) {
throw new GoogleAuthInfoException(uri, "Bad secret", e);
}
if (secret.length == 0) {
throw new GoogleAuthInfoException(uri, "Secret is empty");
}
OtpInfo info;
String issuer = "";
@ -233,6 +236,10 @@ public class GoogleAuthInfo implements Transferable, Serializable {
}
byte[] secret = params.getSecret().toByteArray();
if (secret.length == 0) {
throw new GoogleAuthInfoException(uri, "Secret is empty");
}
switch (params.getType()) {
case OTP_TYPE_UNSPECIFIED:
// intentional fallthrough

View file

@ -30,7 +30,9 @@ public class GoogleAuthInfoException extends Exception {
@Override
public String getMessage() {
Throwable cause = getCause();
if (cause == null) {
if (cause == null
|| this == cause
|| (super.getMessage() != null && super.getMessage().equals(cause.getMessage()))) {
return super.getMessage();
}

View file

@ -30,7 +30,9 @@ public class HotpInfo extends OtpInfo {
}
@Override
public String getOtp() {
public String getOtp() throws OtpInfoException {
checkSecret();
try {
OTP otp = HOTP.generateOTP(getSecret(), getAlgorithm(true), getDigits(), getCounter());
return otp.toString();

View file

@ -28,7 +28,13 @@ public abstract class OtpInfo implements Serializable {
setDigits(digits);
}
public abstract String getOtp();
public abstract String getOtp() throws OtpInfoException;
protected void checkSecret() throws OtpInfoException {
if (getSecret().length == 0) {
throw new OtpInfoException("Secret is empty");
}
}
public abstract String getTypeId();

View file

@ -20,7 +20,9 @@ public class SteamInfo extends TotpInfo {
}
@Override
public String getOtp() {
public String getOtp() throws OtpInfoException {
checkSecret();
try {
OTP otp = TOTP.generateOTP(getSecret(), getAlgorithm(true), getDigits(), getPeriod());
return otp.toSteamString();

View file

@ -26,7 +26,9 @@ public class TotpInfo extends OtpInfo {
}
@Override
public String getOtp() {
public String getOtp() throws OtpInfoException {
checkSecret();
try {
OTP otp = TOTP.generateOTP(getSecret(), getAlgorithm(true), getDigits(), getPeriod());
return otp.toString();

View file

@ -41,6 +41,8 @@ import com.beemdevelopment.aegis.helpers.FabScrollHelper;
import com.beemdevelopment.aegis.helpers.PermissionHelper;
import com.beemdevelopment.aegis.otp.GoogleAuthInfo;
import com.beemdevelopment.aegis.otp.GoogleAuthInfoException;
import com.beemdevelopment.aegis.otp.OtpInfo;
import com.beemdevelopment.aegis.otp.OtpInfoException;
import com.beemdevelopment.aegis.ui.dialogs.Dialogs;
import com.beemdevelopment.aegis.ui.fragments.preferences.BackupsPreferencesFragment;
import com.beemdevelopment.aegis.ui.fragments.preferences.PreferencesFragment;
@ -931,8 +933,15 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene
@SuppressLint("InlinedApi")
private void copyEntryCode(VaultEntry entry) {
String otp;
try {
otp = entry.getInfo().getOtp();
} catch (OtpInfoException e) {
return;
}
ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clip = ClipData.newPlainText("text/plain", entry.getInfo().getOtp());
ClipData clip = ClipData.newPlainText("text/plain", otp);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
PersistableBundle extras = new PersistableBundle();
extras.putBoolean(ClipDescription.EXTRA_IS_SENSITIVE, true);

View file

@ -20,6 +20,7 @@ import com.beemdevelopment.aegis.helpers.ThemeHelper;
import com.beemdevelopment.aegis.helpers.UiRefresher;
import com.beemdevelopment.aegis.otp.HotpInfo;
import com.beemdevelopment.aegis.otp.OtpInfo;
import com.beemdevelopment.aegis.otp.OtpInfoException;
import com.beemdevelopment.aegis.otp.SteamInfo;
import com.beemdevelopment.aegis.otp.TotpInfo;
import com.beemdevelopment.aegis.otp.YandexInfo;
@ -238,9 +239,18 @@ public class EntryHolder extends RecyclerView.ViewHolder {
private void updateCode() {
OtpInfo info = _entry.getInfo();
String otp = info.getOtp();
if (!(info instanceof SteamInfo || info instanceof YandexInfo)) {
otp = formatCode(otp);
// In previous versions of Aegis, it was possible to import entries with an empty
// secret. Attempting to generate OTP's for such entries would result in a crash.
// In case we encounter an old entry that has this issue, we display "ERROR" as
// the OTP, instead of crashing.
String otp;
try {
otp = info.getOtp();
if (!(info instanceof SteamInfo || info instanceof YandexInfo)) {
otp = formatCode(otp);
}
} catch (OtpInfoException e) {
otp = _view.getResources().getString(R.string.error_all_caps);
}
_profileCode.setText(otp);