Add the ability to show qr codes of stored accounts
Signed-off-by: Tilo Spannagel <development@tilosp.de>
This commit is contained in:
parent
b8b9834f06
commit
5a165fd212
4 changed files with 86 additions and 0 deletions
|
@ -276,6 +276,46 @@ public class Entry {
|
||||||
return jsonObj;
|
return jsonObj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Uri toUri() {
|
||||||
|
String type;
|
||||||
|
switch (this.type) {
|
||||||
|
case TOTP:
|
||||||
|
type = "totp";
|
||||||
|
break;
|
||||||
|
case HOTP:
|
||||||
|
type = "hotp";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Uri.Builder builder = new Uri.Builder()
|
||||||
|
.scheme("otpauth")
|
||||||
|
.authority(type)
|
||||||
|
.appendPath(this.label)
|
||||||
|
.appendQueryParameter("secret", new Base32().encodeAsString(this.secret));
|
||||||
|
if (this.issuer != null) {
|
||||||
|
builder.appendQueryParameter("issuer", this.issuer);
|
||||||
|
}
|
||||||
|
switch (this.type) {
|
||||||
|
case HOTP:
|
||||||
|
builder.appendQueryParameter("counter", Long.toString(this.counter));
|
||||||
|
case TOTP:
|
||||||
|
if (this.period != TokenCalculator.TOTP_DEFAULT_PERIOD)
|
||||||
|
builder.appendQueryParameter("period", Integer.toString(this.period));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (this.digits != TokenCalculator.TOTP_DEFAULT_DIGITS) {
|
||||||
|
builder.appendQueryParameter("digits", Integer.toString(this.digits));
|
||||||
|
}
|
||||||
|
if (this.algorithm != TokenCalculator.DEFAULT_ALGORITHM) {
|
||||||
|
builder.appendQueryParameter("algorithm", this.algorithm.name());
|
||||||
|
}
|
||||||
|
for (String tag : this.tags) {
|
||||||
|
builder.appendQueryParameter("tags", tag);
|
||||||
|
}
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isTimeBased() {
|
public boolean isTimeBased() {
|
||||||
return type == OTPType.TOTP || type == OTPType.STEAM;
|
return type == OTPType.TOTP || type == OTPType.STEAM;
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,8 @@ import android.content.ClipData;
|
||||||
import android.content.ClipboardManager;
|
import android.content.ClipboardManager;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.drawable.BitmapDrawable;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
@ -46,9 +48,13 @@ import android.widget.Filter;
|
||||||
import android.widget.Filterable;
|
import android.widget.Filterable;
|
||||||
import android.widget.FrameLayout;
|
import android.widget.FrameLayout;
|
||||||
import android.widget.GridView;
|
import android.widget.GridView;
|
||||||
|
import android.widget.ImageView;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import com.google.zxing.BarcodeFormat;
|
||||||
|
import com.journeyapps.barcodescanner.BarcodeEncoder;
|
||||||
|
|
||||||
import org.shadowice.flocke.andotp.Activities.MainActivity;
|
import org.shadowice.flocke.andotp.Activities.MainActivity;
|
||||||
import org.shadowice.flocke.andotp.Database.Entry;
|
import org.shadowice.flocke.andotp.Database.Entry;
|
||||||
import org.shadowice.flocke.andotp.Dialogs.TagsDialog;
|
import org.shadowice.flocke.andotp.Dialogs.TagsDialog;
|
||||||
|
@ -681,6 +687,35 @@ public class EntriesCardAdapter extends RecyclerView.Adapter<EntryViewHolder>
|
||||||
.show();
|
.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void showQRCode(final int pos) {
|
||||||
|
Uri uri = displayedEntries.get(pos).toUri();
|
||||||
|
if (uri != null) {
|
||||||
|
Bitmap bitmap;
|
||||||
|
try {
|
||||||
|
bitmap = new BarcodeEncoder().encodeBitmap(uri.toString(), BarcodeFormat.QR_CODE, 0, 0);
|
||||||
|
} catch(Exception ignored) {
|
||||||
|
Toast.makeText(context, R.string.toast_qr_failed_to_generate, Toast.LENGTH_LONG).show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
BitmapDrawable drawable = new BitmapDrawable(context.getResources(), bitmap);
|
||||||
|
drawable.setFilterBitmap(false);
|
||||||
|
|
||||||
|
ImageView image = new ImageView(context);
|
||||||
|
image.setAdjustViewBounds(true);
|
||||||
|
image.setScaleType(ImageView.ScaleType.FIT_CENTER);
|
||||||
|
image.setImageDrawable(drawable);
|
||||||
|
|
||||||
|
new AlertDialog.Builder(context)
|
||||||
|
.setTitle(R.string.dialog_title_qr_code)
|
||||||
|
.setPositiveButton(android.R.string.ok, (dialog, which) -> {})
|
||||||
|
.setView(image)
|
||||||
|
.create()
|
||||||
|
.show();
|
||||||
|
} else {
|
||||||
|
Toast.makeText(context, R.string.toast_qr_unsuported, Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void showPopupMenu(View view, final int pos) {
|
private void showPopupMenu(View view, final int pos) {
|
||||||
View menuItemView = view.findViewById(R.id.menuButton);
|
View menuItemView = view.findViewById(R.id.menuButton);
|
||||||
PopupMenu popup = new PopupMenu(view.getContext(), menuItemView);
|
PopupMenu popup = new PopupMenu(view.getContext(), menuItemView);
|
||||||
|
@ -707,6 +742,9 @@ public class EntriesCardAdapter extends RecyclerView.Adapter<EntryViewHolder>
|
||||||
} else if (id == R.id.menu_popup_remove) {
|
} else if (id == R.id.menu_popup_remove) {
|
||||||
removeItem(pos);
|
removeItem(pos);
|
||||||
return true;
|
return true;
|
||||||
|
} else if (id == R.id.menu_popup_show_qr_code) {
|
||||||
|
showQRCode(pos);
|
||||||
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,4 +20,8 @@
|
||||||
android:id="@+id/menu_popup_remove"
|
android:id="@+id/menu_popup_remove"
|
||||||
android:title="@string/menu_popup_remove" />
|
android:title="@string/menu_popup_remove" />
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/menu_popup_show_qr_code"
|
||||||
|
android:title="@string/menu_popup_show_qr_code" />
|
||||||
|
|
||||||
</menu>
|
</menu>
|
|
@ -57,6 +57,7 @@
|
||||||
<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>
|
||||||
<string name="menu_popup_remove">Remove</string>
|
<string name="menu_popup_remove">Remove</string>
|
||||||
|
<string name="menu_popup_show_qr_code">Show QR Code</string>
|
||||||
|
|
||||||
<!-- Toast messages -->
|
<!-- Toast messages -->
|
||||||
<string name="toast_auth_failed">Authentication failed, please try again!</string>
|
<string name="toast_auth_failed">Authentication failed, please try again!</string>
|
||||||
|
@ -71,6 +72,8 @@
|
||||||
<string name="toast_qr_error">Could not find/confirm QR code</string>
|
<string name="toast_qr_error">Could not find/confirm QR code</string>
|
||||||
<string name="toast_qr_checksum_exception">Checksum verification failed while decoding QR code</string>
|
<string name="toast_qr_checksum_exception">Checksum verification failed while decoding QR code</string>
|
||||||
<string name="toast_qr_format_error">Format error in QR code</string>
|
<string name="toast_qr_format_error">Format error in QR code</string>
|
||||||
|
<string name="toast_qr_unsuported">QR Code not supported</string>
|
||||||
|
<string name="toast_qr_failed_to_generate">Failed to generate QR Code</string>
|
||||||
|
|
||||||
<!-- Dialogs -->
|
<!-- Dialogs -->
|
||||||
<string name="dialog_title_auth">Authenticate</string>
|
<string name="dialog_title_auth">Authenticate</string>
|
||||||
|
@ -80,6 +83,7 @@
|
||||||
<string name="dialog_title_counter">Counter</string>
|
<string name="dialog_title_counter">Counter</string>
|
||||||
<string name="dialog_title_used_tokens">Used tokens</string>
|
<string name="dialog_title_used_tokens">Used tokens</string>
|
||||||
<string name="dialog_title_keystore_error">KeyStore error</string>
|
<string name="dialog_title_keystore_error">KeyStore error</string>
|
||||||
|
<string name="dialog_title_qr_code">QR Code</string>
|
||||||
|
|
||||||
<string name="dialog_title_enter_password">Enter password</string>
|
<string name="dialog_title_enter_password">Enter password</string>
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue