Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nextcloud/passman-android.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbinsky08 <timo@binsky.org>2022-08-27 01:06:37 +0300
committerbinsky08 <timo@binsky.org>2022-08-27 01:06:37 +0300
commit506e288df031c54a6905e0de276a3f36eab3fdf6 (patch)
tree4959f1cec49e28275bfa55a00bd8d14d0964c418
parent5f77ef740385b444d1e5284d4a44a6c38933dd3c (diff)
implement otp qr code scanner
Signed-off-by: binsky08 <timo@binsky.org>
-rw-r--r--app/build.gradle2
-rw-r--r--app/src/main/AndroidManifest.xml1
-rw-r--r--app/src/main/java/es/wolfi/app/passman/activities/PasswordListActivity.java31
-rw-r--r--app/src/main/java/es/wolfi/app/passman/fragments/CredentialEditFragment.java51
-rw-r--r--app/src/main/res/layout/content_otp_edit.xml110
-rw-r--r--app/src/main/res/values/strings.xml1
6 files changed, 153 insertions, 43 deletions
diff --git a/app/build.gradle b/app/build.gradle
index 3a55966..4007b45 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -120,6 +120,8 @@ dependencies {
implementation 'com.caverock:androidsvg:1.4'
implementation 'org.bouncycastle:bcpkix-jdk15on:1.70'
implementation 'com.vdurmont:semver4j:3.1.0'
+ implementation('com.journeyapps:zxing-android-embedded:4.3.0') { transitive = false }
+ implementation 'com.google.zxing:core:3.4.0'
testImplementation 'junit:junit:4.13.2'
annotationProcessor 'com.jakewharton:butterknife-compiler:10.2.3'
}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 50b0a58..4045fda 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -5,6 +5,7 @@
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
+ <uses-permission android:name="android.permission.CAMERA" />
<queries>
<package android:name="com.nextcloud.client" />
<package android:name="com.nextcloud.android.beta" />
diff --git a/app/src/main/java/es/wolfi/app/passman/activities/PasswordListActivity.java b/app/src/main/java/es/wolfi/app/passman/activities/PasswordListActivity.java
index 61bad4b..d3cb942 100644
--- a/app/src/main/java/es/wolfi/app/passman/activities/PasswordListActivity.java
+++ b/app/src/main/java/es/wolfi/app/passman/activities/PasswordListActivity.java
@@ -22,6 +22,8 @@
package es.wolfi.app.passman.activities;
+import static com.google.zxing.integration.android.IntentIntegrator.parseActivityResult;
+
import android.app.KeyguardManager;
import android.app.ProgressDialog;
import android.content.ClipData;
@@ -56,6 +58,9 @@ import androidx.core.graphics.drawable.IconCompat;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
+import com.google.zxing.integration.android.IntentResult;
+import com.journeyapps.barcodescanner.ScanContract;
+import com.journeyapps.barcodescanner.ScanOptions;
import com.koushikdutta.async.future.FutureCallback;
import org.json.JSONException;
@@ -100,6 +105,7 @@ public class PasswordListActivity extends AppCompatActivity implements
private static final int REQUEST_CODE_KEYGUARD = 0;
private static final int REQUEST_CODE_AUTHENTICATE = 1;
private static final int REQUEST_CODE_CREATE_DOCUMENT = 2;
+ private static final int REQUEST_CODE_SCAN_QR_CODE_FOR_OTP_EDIT = 7;
static boolean running = false;
@@ -754,6 +760,17 @@ public class PasswordListActivity extends AppCompatActivity implements
startActivityForResult(intent, activityRequestFileCode);
}
+ public void scanQRCodeForOTP() {
+ ScanOptions scanOptions = new ScanOptions();
+ scanOptions.setDesiredBarcodeFormats(ScanOptions.QR_CODE); // optional
+ scanOptions.setOrientationLocked(false); // allow barcode scanner in portrait mode
+
+ ScanContract scanContract = new ScanContract();
+ Intent intent = scanContract.createIntent(this, scanOptions);
+
+ startActivityForResult(intent, REQUEST_CODE_SCAN_QR_CODE_FOR_OTP_EDIT);
+ }
+
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
@@ -777,6 +794,20 @@ public class PasswordListActivity extends AppCompatActivity implements
}
}
+ if (requestCode == REQUEST_CODE_SCAN_QR_CODE_FOR_OTP_EDIT) { // scan qr code as otp config in credential edit
+ if (resultCode != RESULT_OK) {
+ Log.e("otp qr scan", "failed");
+ return;
+ }
+
+ CredentialEditFragment credentialEditFragment = (CredentialEditFragment) getSupportFragmentManager().findFragmentByTag("credentialEdit");
+ if (credentialEditFragment != null) {
+ IntentResult result = parseActivityResult(resultCode, data);
+ credentialEditFragment.processScannedQRCodeData(result.getContents(), requestCode);
+ }
+ Log.e("otp qr scan", "successful");
+ }
+
// Following cases should only be handled on positive result
if (resultCode != RESULT_OK)
return;
diff --git a/app/src/main/java/es/wolfi/app/passman/fragments/CredentialEditFragment.java b/app/src/main/java/es/wolfi/app/passman/fragments/CredentialEditFragment.java
index 558d7fb..57b6e04 100644
--- a/app/src/main/java/es/wolfi/app/passman/fragments/CredentialEditFragment.java
+++ b/app/src/main/java/es/wolfi/app/passman/fragments/CredentialEditFragment.java
@@ -25,9 +25,11 @@ import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
+import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
+import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -102,6 +104,8 @@ public class CredentialEditFragment extends Fragment implements View.OnClickList
EditText otp_secret;
EditText otp_digits;
EditText otp_period;
+ EditText otp_label;
+ EditText otp_issuer;
TextView credential_otp;
ProgressBar otp_progress;
@@ -177,6 +181,8 @@ public class CredentialEditFragment extends Fragment implements View.OnClickList
otp_secret = view.findViewById(R.id.edit_credential_otp_secret);
otp_digits = view.findViewById(R.id.edit_credential_otp_digits);
otp_period = view.findViewById(R.id.edit_credential_otp_period);
+ otp_label = view.findViewById(R.id.otp_label);
+ otp_issuer = view.findViewById(R.id.otp_issuer);
credential_otp = view.findViewById(R.id.credential_otp);
otp_progress = view.findViewById(R.id.credential_otp_progress);
@@ -228,10 +234,10 @@ public class CredentialEditFragment extends Fragment implements View.OnClickList
if (otpObj.has("secret") && otpObj.getString("secret").length() > 4) {
String otpSecret = otpObj.getString("secret");
otp_secret.setText(otpSecret);
-
- handler = new Handler();
- otp_refresh = TOTPHelper.runAndUpdate(handler, otp_progress, credential_otp, otp_digits, otp_period, otp_secret);
}
+
+ handler = new Handler();
+ otp_refresh = TOTPHelper.runAndUpdate(handler, otp_progress, credential_otp, otp_digits, otp_period, otp_secret);
} catch (JSONException e) {
e.printStackTrace();
}
@@ -285,11 +291,46 @@ public class CredentialEditFragment extends Fragment implements View.OnClickList
}, 100);
}
+ public void processScannedQRCodeData(String value, int requestCode) {
+ Log.d("CredentialEdit", "processScannedQRCodeData begins");
+
+ try {
+ JSONObject otpObj = new JSONObject(credential.getOtp());
+ otpObj.put("qr_uri", value);
+
+ Uri uri = Uri.parse(value);
+
+ String type = uri.getHost().equals("totp") ? "totp" : "hotp";
+ otpObj.put("type", type);
+
+ String label = uri.getPath().replaceFirst("/", "");
+ otpObj.put("label", label);
+
+ String algo = uri.getQueryParameter("algorithm");
+ String period = uri.getQueryParameter("period");
+ String digits = uri.getQueryParameter("digits");
+ String issuer = uri.getQueryParameter("issuer");
+
+ otpObj.put("algorithm", algo != null && !algo.isEmpty() ? uri.getQueryParameter("algorithm") : "SHA1");
+
+ otp_period.setText(period != null && !period.isEmpty() ? uri.getQueryParameter("period") : "30");
+ otp_digits.setText(digits != null && !digits.isEmpty() ? uri.getQueryParameter("digits") : "6");
+ otp_label.setText(label);
+ otp_issuer.setText(issuer != null && !issuer.isEmpty() ? issuer : "");
+ otp_secret.setText(uri.getQueryParameter("secret") != null ? uri.getQueryParameter("secret") : "");
+
+ Log.d("CredentialEdit", "processScannedQRCodeData done");
+ } catch (JSONException e) {
+ e.printStackTrace();
+ Log.d("CredentialEdit", "processScannedQRCodeData failed");
+ }
+ }
+
public View.OnClickListener getScanOtpQRCodeButtonListener() {
return new View.OnClickListener() {
@Override
public void onClick(View view) {
- // todo
+ ((PasswordListActivity) requireActivity()).scanQRCodeForOTP();
}
};
}
@@ -299,7 +340,7 @@ public class CredentialEditFragment extends Fragment implements View.OnClickList
@Override
public void onClick(View view) {
if (otp_edit_extended.getVisibility() == View.VISIBLE) {
- otp_edit_extended.setVisibility(View.INVISIBLE);
+ otp_edit_extended.setVisibility(View.GONE);
otpEditCollapseExtendedButton.setRotation(-90);
} else {
otp_edit_extended.setVisibility(View.VISIBLE);
diff --git a/app/src/main/res/layout/content_otp_edit.xml b/app/src/main/res/layout/content_otp_edit.xml
index 2391870..2931ad5 100644
--- a/app/src/main/res/layout/content_otp_edit.xml
+++ b/app/src/main/res/layout/content_otp_edit.xml
@@ -55,14 +55,14 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:animateLayoutChanges="true"
- android:gravity="center"
+ android:gravity="start|top"
android:orientation="horizontal">
<androidx.appcompat.widget.AppCompatImageButton
android:id="@+id/otpEditCollapseExtendedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_gravity="end|center_vertical"
+ android:layout_gravity="top|center_vertical"
android:layout_marginTop="0dp"
android:layout_marginBottom="0dp"
android:backgroundTint="@color/transparent"
@@ -75,56 +75,90 @@
android:layout_height="wrap_content"
android:animateLayoutChanges="true"
android:gravity="center"
- android:orientation="horizontal"
- android:visibility="invisible">
+ android:orientation="vertical"
+ android:visibility="visible">
- <LinearLayout
- android:layout_width="150dp"
+ <TextView
+ style="@style/Label"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:orientation="vertical">
+ android:text="@string/label" />
- <TextView
- style="@style/Label"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/digits" />
+ <EditText
+ android:id="@+id/otp_label"
+ style="@style/FormText"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:hint="@string/label" />
- <EditText
- android:id="@+id/edit_credential_otp_digits"
- style="@style/FormText"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginEnd="30dp"
- android:digits="0123456789"
- android:hint="6"
- android:inputType="number" />
+ <TextView
+ style="@style/Label"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/issuer" />
+
+ <EditText
+ android:id="@+id/otp_issuer"
+ style="@style/FormText"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:hint="@string/issuer" />
- </LinearLayout>
<LinearLayout
- android:layout_width="150dp"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:orientation="vertical">
+ android:animateLayoutChanges="true"
+ android:orientation="horizontal">
- <TextView
- style="@style/Label"
- android:layout_width="match_parent"
+ <LinearLayout
+ android:layout_width="160dp"
android:layout_height="wrap_content"
- android:text="@string/period" />
-
- <EditText
- android:id="@+id/edit_credential_otp_period"
- style="@style/FormText"
- android:layout_width="match_parent"
+ android:orientation="vertical"
+ android:layout_marginEnd="12dp">
+
+ <TextView
+ style="@style/Label"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/digits" />
+
+ <EditText
+ android:id="@+id/edit_credential_otp_digits"
+ style="@style/FormText"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:digits="0123456789"
+ android:hint="6"
+ android:inputType="number" />
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="160dp"
android:layout_height="wrap_content"
- android:layout_marginEnd="30dp"
- android:digits="0123456789"
- android:hint="30"
- android:inputType="number" />
+ android:orientation="vertical">
- </LinearLayout>
+ <TextView
+ style="@style/Label"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/period" />
+
+ <EditText
+ android:id="@+id/edit_credential_otp_period"
+ style="@style/FormText"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:digits="0123456789"
+ android:hint="30"
+ android:inputType="number" />
+ </LinearLayout>
+
+ </LinearLayout>
</LinearLayout>
+
</LinearLayout>
</LinearLayout>
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 0e65f91..3f986ce 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -90,4 +90,5 @@
<string name="digits">Digits</string>
<string name="period">Period</string>
<string name="secret">Secret</string>
+ <string name="issuer">Issuer</string>
</resources>