Save and show issuer and label separately
This commit is contained in:
parent
2f77fe4644
commit
5db1c587b3
8 changed files with 121 additions and 9 deletions
|
@ -50,6 +50,7 @@ public class Entry {
|
||||||
private static final int DEFAULT_PERIOD = 30;
|
private static final int DEFAULT_PERIOD = 30;
|
||||||
|
|
||||||
private static final String JSON_SECRET = "secret";
|
private static final String JSON_SECRET = "secret";
|
||||||
|
private static final String JSON_ISSUER = "issuer";
|
||||||
private static final String JSON_LABEL = "label";
|
private static final String JSON_LABEL = "label";
|
||||||
private static final String JSON_PERIOD = "period";
|
private static final String JSON_PERIOD = "period";
|
||||||
private static final String JSON_COUNTER = "counter";
|
private static final String JSON_COUNTER = "counter";
|
||||||
|
@ -66,6 +67,7 @@ public class Entry {
|
||||||
private TokenCalculator.HashAlgorithm algorithm = TokenCalculator.DEFAULT_ALGORITHM;
|
private TokenCalculator.HashAlgorithm algorithm = TokenCalculator.DEFAULT_ALGORITHM;
|
||||||
private byte[] secret;
|
private byte[] secret;
|
||||||
private long counter;
|
private long counter;
|
||||||
|
private String issuer;
|
||||||
private String label;
|
private String label;
|
||||||
private String currentOTP;
|
private String currentOTP;
|
||||||
private boolean visible = false;
|
private boolean visible = false;
|
||||||
|
@ -77,21 +79,23 @@ public class Entry {
|
||||||
|
|
||||||
public Entry(){}
|
public Entry(){}
|
||||||
|
|
||||||
public Entry(OTPType type, String secret, int period, int digits, String label, TokenCalculator.HashAlgorithm algorithm, List<String> tags) {
|
public Entry(OTPType type, String secret, int period, int digits, String issuer, String label, TokenCalculator.HashAlgorithm algorithm, List<String> tags) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.secret = new Base32().decode(secret.toUpperCase());
|
this.secret = new Base32().decode(secret.toUpperCase());
|
||||||
this.period = period;
|
this.period = period;
|
||||||
this.digits = digits;
|
this.digits = digits;
|
||||||
|
this.issuer = issuer;
|
||||||
this.label = label;
|
this.label = label;
|
||||||
this.algorithm = algorithm;
|
this.algorithm = algorithm;
|
||||||
this.tags = tags;
|
this.tags = tags;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Entry(OTPType type, String secret, long counter, int digits, String label, TokenCalculator.HashAlgorithm algorithm, List<String> tags) {
|
public Entry(OTPType type, String secret, long counter, int digits, String issuer, String label, TokenCalculator.HashAlgorithm algorithm, List<String> tags) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.secret = new Base32().decode(secret.toUpperCase());
|
this.secret = new Base32().decode(secret.toUpperCase());
|
||||||
this.counter = counter;
|
this.counter = counter;
|
||||||
this.digits = digits;
|
this.digits = digits;
|
||||||
|
this.issuer = issuer;
|
||||||
this.label = label;
|
this.label = label;
|
||||||
this.algorithm = algorithm;
|
this.algorithm = algorithm;
|
||||||
this.tags = tags;
|
this.tags = tags;
|
||||||
|
@ -124,10 +128,6 @@ public class Entry {
|
||||||
String algorithm = uri.getQueryParameter("algorithm");
|
String algorithm = uri.getQueryParameter("algorithm");
|
||||||
List<String> tags = uri.getQueryParameters("tags");
|
List<String> tags = uri.getQueryParameters("tags");
|
||||||
|
|
||||||
if (issuer != null){
|
|
||||||
label = issuer +" - "+label;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type == OTPType.HOTP) {
|
if (type == OTPType.HOTP) {
|
||||||
if (counter != null) {
|
if (counter != null) {
|
||||||
this.counter = Long.parseLong(counter);
|
this.counter = Long.parseLong(counter);
|
||||||
|
@ -142,6 +142,7 @@ public class Entry {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.issuer = issuer;
|
||||||
this.label = label;
|
this.label = label;
|
||||||
this.secret = new Base32().decode(secret.toUpperCase());
|
this.secret = new Base32().decode(secret.toUpperCase());
|
||||||
|
|
||||||
|
@ -169,6 +170,13 @@ public class Entry {
|
||||||
this.secret = new Base32().decode(jsonObj.getString(JSON_SECRET).toUpperCase());
|
this.secret = new Base32().decode(jsonObj.getString(JSON_SECRET).toUpperCase());
|
||||||
this.label = jsonObj.getString(JSON_LABEL);
|
this.label = jsonObj.getString(JSON_LABEL);
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.issuer = jsonObj.getString(JSON_ISSUER);
|
||||||
|
} catch (JSONException e) {
|
||||||
|
// Older backup version did not save issuer and label separately
|
||||||
|
this.issuer = "";
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this.type = OTPType.valueOf(jsonObj.getString(JSON_TYPE));
|
this.type = OTPType.valueOf(jsonObj.getString(JSON_TYPE));
|
||||||
} catch(Exception e) {
|
} catch(Exception e) {
|
||||||
|
@ -227,6 +235,7 @@ public class Entry {
|
||||||
public JSONObject toJSON() throws JSONException {
|
public JSONObject toJSON() throws JSONException {
|
||||||
JSONObject jsonObj = new JSONObject();
|
JSONObject jsonObj = new JSONObject();
|
||||||
jsonObj.put(JSON_SECRET, new String(new Base32().encode(getSecret())));
|
jsonObj.put(JSON_SECRET, new String(new Base32().encode(getSecret())));
|
||||||
|
jsonObj.put(JSON_ISSUER, getIssuer());
|
||||||
jsonObj.put(JSON_LABEL, getLabel());
|
jsonObj.put(JSON_LABEL, getLabel());
|
||||||
jsonObj.put(JSON_DIGITS, getDigits());
|
jsonObj.put(JSON_DIGITS, getDigits());
|
||||||
jsonObj.put(JSON_TYPE, getType().toString());
|
jsonObj.put(JSON_TYPE, getType().toString());
|
||||||
|
@ -268,6 +277,14 @@ public class Entry {
|
||||||
this.secret = secret;
|
this.secret = secret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getIssuer() {
|
||||||
|
return issuer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIssuer(String issuer) {
|
||||||
|
this.issuer = issuer;
|
||||||
|
}
|
||||||
|
|
||||||
public String getLabel() {
|
public String getLabel() {
|
||||||
return label;
|
return label;
|
||||||
}
|
}
|
||||||
|
|
|
@ -371,6 +371,51 @@ public class EntriesCardAdapter extends RecyclerView.Adapter<EntryViewHolder>
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void editEntryIssuer(final int pos) {
|
||||||
|
AlertDialog.Builder builder = new AlertDialog.Builder(context);
|
||||||
|
|
||||||
|
int marginSmall = context.getResources().getDimensionPixelSize(R.dimen.activity_margin_small);
|
||||||
|
int marginMedium = context.getResources().getDimensionPixelSize(R.dimen.activity_margin_medium);
|
||||||
|
|
||||||
|
final EditText input = new EditText(context);
|
||||||
|
input.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
|
||||||
|
input.setText(displayedEntries.get(pos).getIssuer());
|
||||||
|
input.setSingleLine();
|
||||||
|
|
||||||
|
FrameLayout container = new FrameLayout(context);
|
||||||
|
container.setPaddingRelative(marginMedium, marginSmall, marginMedium, 0);
|
||||||
|
container.addView(input);
|
||||||
|
|
||||||
|
builder.setTitle(R.string.dialog_title_rename)
|
||||||
|
.setView(container)
|
||||||
|
.setPositiveButton(R.string.button_save, new DialogInterface.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialogInterface, int i) {
|
||||||
|
int realIndex = getRealIndex(pos);
|
||||||
|
String newIssuer = input.getEditableText().toString();
|
||||||
|
|
||||||
|
displayedEntries.get(pos).setIssuer(newIssuer);
|
||||||
|
if (sortMode == SortMode.LABEL) {
|
||||||
|
displayedEntries = sortEntries(displayedEntries);
|
||||||
|
notifyDataSetChanged();
|
||||||
|
} else {
|
||||||
|
notifyItemChanged(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
Entry e = entries.get(realIndex);
|
||||||
|
e.setIssuer(newIssuer);
|
||||||
|
|
||||||
|
DatabaseHelper.saveDatabase(context, entries, encryptionKey);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialogInterface, int i) {}
|
||||||
|
})
|
||||||
|
.create()
|
||||||
|
.show();
|
||||||
|
}
|
||||||
|
|
||||||
public void editEntryLabel(final int pos) {
|
public void editEntryLabel(final int pos) {
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(context);
|
AlertDialog.Builder builder = new AlertDialog.Builder(context);
|
||||||
|
|
||||||
|
@ -585,7 +630,10 @@ public class EntriesCardAdapter extends RecyclerView.Adapter<EntryViewHolder>
|
||||||
public boolean onMenuItemClick(MenuItem item) {
|
public boolean onMenuItemClick(MenuItem item) {
|
||||||
int id = item.getItemId();
|
int id = item.getItemId();
|
||||||
|
|
||||||
if (id == R.id.menu_popup_editLabel) {
|
if (id == R.id.menu_popup_editIssuer) {
|
||||||
|
editEntryIssuer(pos);
|
||||||
|
return true;
|
||||||
|
} else if (id == R.id.menu_popup_editLabel) {
|
||||||
editEntryLabel(pos);
|
editEntryLabel(pos);
|
||||||
return true;
|
return true;
|
||||||
} else if(id == R.id.menu_popup_changeImage) {
|
} else if(id == R.id.menu_popup_changeImage) {
|
||||||
|
|
|
@ -64,6 +64,7 @@ public class EntryViewHolder extends RecyclerView.ViewHolder
|
||||||
private ImageView visibleImg;
|
private ImageView visibleImg;
|
||||||
private ImageView thumbnailImg;
|
private ImageView thumbnailImg;
|
||||||
private TextView value;
|
private TextView value;
|
||||||
|
private TextView issuer;
|
||||||
private TextView label;
|
private TextView label;
|
||||||
private TextView counter;
|
private TextView counter;
|
||||||
private TextView tags;
|
private TextView tags;
|
||||||
|
@ -81,6 +82,7 @@ public class EntryViewHolder extends RecyclerView.ViewHolder
|
||||||
thumbnailFrame = v.findViewById(R.id.thumbnailFrame);
|
thumbnailFrame = v.findViewById(R.id.thumbnailFrame);
|
||||||
thumbnailImg = v.findViewById(R.id.thumbnailImg);
|
thumbnailImg = v.findViewById(R.id.thumbnailImg);
|
||||||
coverLayout = v.findViewById(R.id.coverLayout);
|
coverLayout = v.findViewById(R.id.coverLayout);
|
||||||
|
issuer = v.findViewById(R.id.textViewIssuer);
|
||||||
label = v.findViewById(R.id.textViewLabel);
|
label = v.findViewById(R.id.textViewLabel);
|
||||||
tags = v.findViewById(R.id.textViewTags);
|
tags = v.findViewById(R.id.textViewTags);
|
||||||
counterLayout = v.findViewById(R.id.counterLayout);
|
counterLayout = v.findViewById(R.id.counterLayout);
|
||||||
|
@ -149,6 +151,14 @@ public class EntryViewHolder extends RecyclerView.ViewHolder
|
||||||
|
|
||||||
final String tokenFormatted = Tools.formatToken(entry.getCurrentOTP(), settings.getTokenSplitGroupSize());
|
final String tokenFormatted = Tools.formatToken(entry.getCurrentOTP(), settings.getTokenSplitGroupSize());
|
||||||
|
|
||||||
|
String issuerText = entry.getIssuer();
|
||||||
|
if (!TextUtils.isEmpty(issuerText)) {
|
||||||
|
issuer.setText(entry.getIssuer());
|
||||||
|
issuer.setVisibility(View.VISIBLE);
|
||||||
|
} else {
|
||||||
|
issuer.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
|
||||||
label.setText(entry.getLabel());
|
label.setText(entry.getLabel());
|
||||||
value.setText(tokenFormatted);
|
value.setText(tokenFormatted);
|
||||||
// save the unformatted token to the tag of this TextView for copy/paste
|
// save the unformatted token to the tag of this TextView for copy/paste
|
||||||
|
|
|
@ -59,6 +59,7 @@ public class ManualEntryDialog {
|
||||||
View inputView = callingActivity.getLayoutInflater().inflate(R.layout.dialog_manual_entry, container, false);
|
View inputView = callingActivity.getLayoutInflater().inflate(R.layout.dialog_manual_entry, container, false);
|
||||||
|
|
||||||
final Spinner typeInput = inputView.findViewById(R.id.manual_type);
|
final Spinner typeInput = inputView.findViewById(R.id.manual_type);
|
||||||
|
final EditText issuerInput = inputView.findViewById(R.id.manual_issuer);
|
||||||
final EditText labelInput = inputView.findViewById(R.id.manual_label);
|
final EditText labelInput = inputView.findViewById(R.id.manual_label);
|
||||||
final EditText secretInput = inputView.findViewById(R.id.manual_secret);
|
final EditText secretInput = inputView.findViewById(R.id.manual_secret);
|
||||||
final EditText counterInput = inputView.findViewById(R.id.manual_counter);
|
final EditText counterInput = inputView.findViewById(R.id.manual_counter);
|
||||||
|
@ -192,6 +193,7 @@ public class ManualEntryDialog {
|
||||||
Entry.OTPType type = (Entry.OTPType) typeInput.getSelectedItem();
|
Entry.OTPType type = (Entry.OTPType) typeInput.getSelectedItem();
|
||||||
TokenCalculator.HashAlgorithm algorithm = (TokenCalculator.HashAlgorithm) algorithmInput.getSelectedItem();
|
TokenCalculator.HashAlgorithm algorithm = (TokenCalculator.HashAlgorithm) algorithmInput.getSelectedItem();
|
||||||
|
|
||||||
|
String issuer = issuerInput.getText().toString();
|
||||||
String label = labelInput.getText().toString();
|
String label = labelInput.getText().toString();
|
||||||
String secret = secretInput.getText().toString();
|
String secret = secretInput.getText().toString();
|
||||||
int digits = Integer.parseInt(digitsInput.getText().toString());
|
int digits = Integer.parseInt(digitsInput.getText().toString());
|
||||||
|
@ -199,7 +201,7 @@ public class ManualEntryDialog {
|
||||||
if (type == Entry.OTPType.TOTP || type == Entry.OTPType.STEAM) {
|
if (type == Entry.OTPType.TOTP || type == Entry.OTPType.STEAM) {
|
||||||
int period = Integer.parseInt(periodInput.getText().toString());
|
int period = Integer.parseInt(periodInput.getText().toString());
|
||||||
|
|
||||||
Entry e = new Entry(type, secret, period, digits, label, algorithm, tagsAdapter.getActiveTags());
|
Entry e = new Entry(type, secret, period, digits, issuer, label, algorithm, tagsAdapter.getActiveTags());
|
||||||
e.updateOTP();
|
e.updateOTP();
|
||||||
e.setLastUsed(System.currentTimeMillis());
|
e.setLastUsed(System.currentTimeMillis());
|
||||||
adapter.addEntry(e);
|
adapter.addEntry(e);
|
||||||
|
@ -209,7 +211,7 @@ public class ManualEntryDialog {
|
||||||
} else if (type == Entry.OTPType.HOTP) {
|
} else if (type == Entry.OTPType.HOTP) {
|
||||||
long counter = Long.parseLong(counterInput.getText().toString());
|
long counter = Long.parseLong(counterInput.getText().toString());
|
||||||
|
|
||||||
Entry e = new Entry(type, secret, counter, digits, label, algorithm, tagsAdapter.getActiveTags());
|
Entry e = new Entry(type, secret, counter, digits, issuer, label, algorithm, tagsAdapter.getActiveTags());
|
||||||
e.updateOTP();
|
e.updateOTP();
|
||||||
e.setLastUsed(System.currentTimeMillis());
|
e.setLastUsed(System.currentTimeMillis());
|
||||||
adapter.addEntry(e);
|
adapter.addEntry(e);
|
||||||
|
|
|
@ -105,6 +105,15 @@
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/textViewIssuer"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:textSize="18sp"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/textViewLabel"
|
android:id="@+id/textViewLabel"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
|
|
|
@ -32,6 +32,27 @@
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:orientation="horizontal" >
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_weight="3"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/label_issuer"/>
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/manual_issuer"
|
||||||
|
android:layout_weight="7"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="@string/label_issuer"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/menu_popup_editIssuer"
|
||||||
|
android:title="@string/menu_popup_edit_issuer" />
|
||||||
<item
|
<item
|
||||||
android:id="@+id/menu_popup_editLabel"
|
android:id="@+id/menu_popup_editLabel"
|
||||||
android:title="@string/menu_popup_edit_label" />
|
android:title="@string/menu_popup_edit_label" />
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
<string name="label_period">Period</string>
|
<string name="label_period">Period</string>
|
||||||
<string name="label_digits">Digits</string>
|
<string name="label_digits">Digits</string>
|
||||||
<string name="label_counter">Counter</string>
|
<string name="label_counter">Counter</string>
|
||||||
|
<string name="label_issuer">Issuer</string>
|
||||||
<string name="label_label">Label</string>
|
<string name="label_label">Label</string>
|
||||||
<string name="label_algorithm">Algorithm</string>
|
<string name="label_algorithm">Algorithm</string>
|
||||||
<string name="label_tags">Tags</string>
|
<string name="label_tags">Tags</string>
|
||||||
|
@ -47,6 +48,7 @@
|
||||||
<string name="menu_sort_label">Label</string>
|
<string name="menu_sort_label">Label</string>
|
||||||
<string name="menu_sort_last_used">Last used</string>
|
<string name="menu_sort_last_used">Last used</string>
|
||||||
|
|
||||||
|
<string name="menu_popup_edit_issuer">Edit issuer</string>
|
||||||
<string name="menu_popup_edit_label">Edit label</string>
|
<string name="menu_popup_edit_label">Edit label</string>
|
||||||
<string name="menu_popup_change_image">Change image</string>
|
<string name="menu_popup_change_image">Change image</string>
|
||||||
<string name="menu_popup_edit_tags">Edit tags</string>
|
<string name="menu_popup_edit_tags">Edit tags</string>
|
||||||
|
|
Loading…
Reference in a new issue