Răsfoiți Sursa

Merge pull request #3207 from nextcloud/fingerprintBug

Fix fingerprint bug
Andy Scherzinger 6 ani în urmă
părinte
comite
90302c0de0

+ 3 - 1
src/main/AndroidManifest.xml

@@ -245,7 +245,9 @@
         <service android:name=".media.MediaService" />
 
         <activity android:name=".ui.activity.PassCodeActivity" />
-        <activity android:name=".ui.activity.RequestCredentialsActivity" />
+        <activity
+            android:name=".ui.activity.RequestCredentialsActivity"
+            android:launchMode="singleTask" />
         <activity android:name=".ui.activity.ConflictsResolveActivity"/>
         <activity android:name=".ui.activity.ErrorsWhileCopyingHandlerActivity"/>
 

+ 12 - 12
src/main/java/com/owncloud/android/authentication/PassCodeManager.java

@@ -50,12 +50,11 @@ public final class PassCodeManager {
         // other activities may be exempted, if needed
     }
 
-    private static final int PASS_CODE_TIMEOUT = 1000;
+    private static final int PASS_CODE_TIMEOUT = 5000;
         // keeping a "low" positive value is the easiest way to prevent the pass code is requested on rotations
 
     private static PassCodeManager passCodeManagerInstance;
 
-    private Long timestamp = 0L;
     private int visibleActivitiesCounter;
 
     public static PassCodeManager getPassCodeManager() {
@@ -79,7 +78,8 @@ public final class PassCodeManager {
     }
 
     public void onActivityStarted(Activity activity) {
-        if (!exemptOfPasscodeActivities.contains(activity.getClass()) && passCodeShouldBeRequested()) {
+        Long timestamp = PreferenceManager.getLockTimestamp(activity);
+        if (!exemptOfPasscodeActivities.contains(activity.getClass()) && passCodeShouldBeRequested(timestamp)) {
 
             Intent i = new Intent(MainApp.getAppContext(), PassCodeActivity.class);
             i.setAction(PassCodeActivity.ACTION_CHECK);
@@ -88,8 +88,7 @@ public final class PassCodeManager {
         }
 
         if (!exemptOfPasscodeActivities.contains(activity.getClass()) &&
-                Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && deviceCredentialsShouldBeRequested(activity) &&
-                !DeviceCredentialUtils.tryEncrypt(activity)) {
+            Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && deviceCredentialsShouldBeRequested(timestamp, activity)) {
             Intent i = new Intent(MainApp.getAppContext(), RequestCredentialsActivity.class);
             i.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
             activity.startActivityForResult(i, PASSCODE_ACTIVITY);
@@ -102,7 +101,7 @@ public final class PassCodeManager {
         if (visibleActivitiesCounter > 0) {
             visibleActivitiesCounter--;
         }
-        setUnlockTimestamp();
+        setUnlockTimestamp(activity);
         PowerManager powerMgr = (PowerManager) activity.getSystemService(Context.POWER_SERVICE);
         if ((passCodeIsEnabled() || deviceCredentialsAreEnabled(activity)) && powerMgr != null
                 && !powerMgr.isScreenOn()) {
@@ -110,22 +109,23 @@ public final class PassCodeManager {
         }
     }
 
-    private void setUnlockTimestamp() {
-        timestamp = System.currentTimeMillis();
+    private void setUnlockTimestamp(Activity activity) {
+        Long timestamp = System.currentTimeMillis();
+        PreferenceManager.setLockTimestamp(activity, timestamp);
     }
 
-    private boolean passCodeShouldBeRequested() {
+    private boolean passCodeShouldBeRequested(Long timestamp) {
         return (System.currentTimeMillis() - timestamp) > PASS_CODE_TIMEOUT &&
-                visibleActivitiesCounter <= 0 && passCodeIsEnabled();
+            visibleActivitiesCounter <= 0 && passCodeIsEnabled();
     }
 
     private boolean passCodeIsEnabled() {
         return PreferenceManager.getLockPreference(MainApp.getAppContext()).equals(Preferences.LOCK_PASSCODE);
     }
 
-    private boolean deviceCredentialsShouldBeRequested(Activity activity) {
+    private boolean deviceCredentialsShouldBeRequested(Long timestamp, Activity activity) {
         return (System.currentTimeMillis() - timestamp) > PASS_CODE_TIMEOUT && visibleActivitiesCounter <= 0 &&
-                deviceCredentialsAreEnabled(activity);
+            deviceCredentialsAreEnabled(activity);
     }
 
     private boolean deviceCredentialsAreEnabled(Activity activity) {

+ 21 - 7
src/main/java/com/owncloud/android/db/PreferenceManager.java

@@ -3,16 +3,16 @@
  *
  * @author David A. Velasco
  * Copyright (C) 2016 ownCloud Inc.
- * 
+ *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2,
  * as published by the Free Software Foundation.
- * 
+ *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU General Public License
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
@@ -65,6 +65,7 @@ public final class PreferenceManager {
     private static final String PREF__AUTO_UPLOAD_INIT = "autoUploadInit";
     private static final String PREF__FOLDER_SORT_ORDER = "folder_sort_order";
     private static final String PREF__FOLDER_LAYOUT = "folder_layout";
+    public static final String PREF__LOCK_TIMESTAMP = "lock_timestamp";
 
     private PreferenceManager() {
     }
@@ -233,7 +234,7 @@ public final class PreferenceManager {
      *
      * @param context Caller {@link Context}, used to access to preferences manager.
      * @param folder Folder
-     * @return preference value, default is 
+     * @return preference value, default is
      * {@link com.owncloud.android.ui.fragment.OCFileListFragment#FOLDER_LAYOUT_LIST}
      */
     public static String getFolderLayout(Context context, OCFile folder) {
@@ -289,14 +290,14 @@ public final class PreferenceManager {
         if (account == null) {
             return defaultValue;
         }
-        
+
         ArbitraryDataProvider dataProvider = new ArbitraryDataProvider(context.getContentResolver());
         FileDataStorageManager storageManager = ((ComponentsGetter)context).getStorageManager();
 
         if (storageManager == null) {
             storageManager = new FileDataStorageManager(account, context.getContentResolver());
         }
-        
+
         String value = dataProvider.getValue(account.name, getKeyFromFolder(preferenceName, folder));
         while (folder != null && value.isEmpty()) {
             folder = storageManager.getFileById(folder.getParentId());
@@ -322,7 +323,7 @@ public final class PreferenceManager {
     private static String getKeyFromFolder(String preferenceName, OCFile folder) {
         final String folderIdString = String.valueOf(folder != null ? folder.getFileId() :
                 FileDataStorageManager.ROOT_PARENT_ID);
-        
+
         return preferenceName + "_" + folderIdString;
     }
 
@@ -471,6 +472,14 @@ public final class PreferenceManager {
         saveIntPreference(context, AUTO_PREF__LAST_SEEN_VERSION_CODE, versionCode);
     }
 
+    public static long getLockTimestamp(Context context) {
+        return getDefaultSharedPreferences(context).getLong(PREF__LOCK_TIMESTAMP, 0);
+    }
+
+    public static void setLockTimestamp(Context context, long timestamp) {
+        saveLongPreference(context, PREF__LOCK_TIMESTAMP, timestamp);
+    }
+
     private static void saveBooleanPreference(Context context, String key, boolean value) {
         SharedPreferences.Editor appPreferences = getDefaultSharedPreferences(context.getApplicationContext()).edit();
         appPreferences.putBoolean(key, value).apply();
@@ -497,6 +506,11 @@ public final class PreferenceManager {
         appPreferences.putFloat(key, value).apply();
     }
 
+    private static void saveLongPreference(Context context, String key, long value) {
+        SharedPreferences.Editor appPreferences = getDefaultSharedPreferences(context.getApplicationContext()).edit();
+        appPreferences.putLong(key, value).apply();
+    }
+
     public static SharedPreferences getDefaultSharedPreferences(Context context) {
         return android.preference.PreferenceManager.getDefaultSharedPreferences(context.getApplicationContext());
     }

+ 3 - 1
src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java

@@ -67,6 +67,7 @@ import com.owncloud.android.datamodel.ArbitraryDataProvider;
 import com.owncloud.android.datamodel.ExternalLinksProvider;
 import com.owncloud.android.datamodel.FileDataStorageManager;
 import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.db.PreferenceManager;
 import com.owncloud.android.lib.common.ExternalLink;
 import com.owncloud.android.lib.common.ExternalLinkType;
 import com.owncloud.android.lib.common.OwnCloudAccount;
@@ -1252,7 +1253,8 @@ public abstract class DrawerActivity extends ToolbarActivity implements DisplayU
 
             if (result == RequestCredentialsActivity.KEY_CHECK_RESULT_CANCEL) {
                 Log_OC.d(TAG, "PassCodeManager cancelled");
-                super.onBackPressed();
+                PreferenceManager.setLockTimestamp(this, 0);
+                finish();
             }
         }
     }

+ 3 - 3
src/main/java/com/owncloud/android/ui/activity/RequestCredentialsActivity.java

@@ -50,7 +50,7 @@ public class RequestCredentialsActivity extends Activity {
     @Override
     protected void onActivityResult(int requestCode, int resultCode, Intent data) {
         if (requestCode == REQUEST_CODE_CONFIRM_DEVICE_CREDENTIALS) {
-            if (resultCode == Activity.RESULT_OK && DeviceCredentialUtils.tryEncrypt(getApplicationContext())) {
+            if (resultCode == Activity.RESULT_OK) {
                 finishWithResult(KEY_CHECK_RESULT_TRUE);
             } else if (resultCode == Activity.RESULT_CANCELED) {
                 finishWithResult(KEY_CHECK_RESULT_CANCEL);
@@ -66,11 +66,10 @@ public class RequestCredentialsActivity extends Activity {
         super.onResume();
 
         if (DeviceCredentialUtils.areCredentialsAvailable(this)) {
-            DeviceCredentialUtils.createKey(getApplicationContext());
             requestCredentials();
         } else {
             DisplayUtils.showSnackMessage(this, R.string.prefs_lock_device_credentials_not_setup);
-            finishWithResult(KEY_CHECK_RESULT_TRUE);
+            finishWithResult(KEY_CHECK_RESULT_CANCEL);
         }
     }
 
@@ -78,6 +77,7 @@ public class RequestCredentialsActivity extends Activity {
         KeyguardManager keyguardManager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
         if (keyguardManager != null) {
             Intent i = keyguardManager.createConfirmDeviceCredentialIntent(null, null);
+            i.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
             startActivityForResult(i, REQUEST_CODE_CONFIRM_DEVICE_CREDENTIALS);
         } else {
             Log_OC.e(TAG, "Keyguard manager is null");

+ 1 - 86
src/main/java/com/owncloud/android/utils/DeviceCredentialUtils.java

@@ -23,33 +23,10 @@ package com.owncloud.android.utils;
 import android.app.KeyguardManager;
 import android.content.Context;
 import android.os.Build;
-import android.security.keystore.KeyGenParameterSpec;
-import android.security.keystore.KeyProperties;
 import android.support.annotation.RequiresApi;
 
-import com.owncloud.android.R;
 import com.owncloud.android.lib.common.utils.Log_OC;
 
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.nio.IntBuffer;
-import java.security.InvalidAlgorithmParameterException;
-import java.security.InvalidKeyException;
-import java.security.KeyStore;
-import java.security.KeyStoreException;
-import java.security.NoSuchAlgorithmException;
-import java.security.NoSuchProviderException;
-import java.security.ProviderException;
-import java.security.UnrecoverableKeyException;
-import java.security.cert.CertificateException;
-
-import javax.crypto.BadPaddingException;
-import javax.crypto.Cipher;
-import javax.crypto.IllegalBlockSizeException;
-import javax.crypto.KeyGenerator;
-import javax.crypto.NoSuchPaddingException;
-import javax.crypto.SecretKey;
-
 /**
  * Utility class with methods for handling device credentials.
  */
@@ -68,7 +45,7 @@ public final class DeviceCredentialUtils {
 
     public static boolean areCredentialsAvailable(Context context) {
         KeyguardManager keyguardManager = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
-        
+
         if (keyguardManager != null) {
             return keyguardManager.isKeyguardSecure();
         } else {
@@ -76,66 +53,4 @@ public final class DeviceCredentialUtils {
             return false;
         }
     }
-
-    /**
-     * Creates a symmetric key in the Android Key Store which can only be used after the user has
-     * authenticated with device credentials within the last X seconds.
-     */
-    public static void createKey(Context context) {
-        // Generate a key to decrypt payment credentials, tokens, etc.
-        final String keyName = context.getResources().getString(R.string.secret_key_name);
-        try {
-            KeyStore keyStore = KeyStore.getInstance(ANDROID_KEY_STORE);
-            keyStore.load(null);
-            KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, ANDROID_KEY_STORE);
-
-            // Set the alias of the entry in Android KeyStore where the key will appear
-            // and the constrains (purposes) in the constructor of the Builder
-            keyGenerator.init(new KeyGenParameterSpec.Builder(keyName, KeyProperties.PURPOSE_ENCRYPT |
-                    KeyProperties.PURPOSE_DECRYPT)
-                    .setBlockModes(KeyProperties.BLOCK_MODE_CBC)
-                    .setUserAuthenticationRequired(true)
-                    // Require that the user has unlocked in the last 30 seconds
-                    .setUserAuthenticationValidityDurationSeconds(AUTHENTICATION_DURATION_SECONDS)
-                    .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7)
-                    .build());
-            keyGenerator.generateKey();
-        } catch (NoSuchAlgorithmException | NoSuchProviderException
-                | InvalidAlgorithmParameterException | KeyStoreException
-                | CertificateException | ProviderException | IOException e) {
-            Log_OC.e(TAG, "Exception: " + e.getMessage());
-        }
-    }
-
-    /**
-     * Tries to encrypt some data with the generated key in {@link #createKey} which
-     * only works if the user has just authenticated via device credentials.
-     */
-    public static boolean tryEncrypt(Context context) {
-        try {
-            final String keyName = context.getResources().getString(R.string.secret_key_name);
-            final int[] secretIntArray = context.getResources().getIntArray(R.array.secret_byte_array);
-            ByteBuffer byteBuffer = ByteBuffer.allocate(secretIntArray.length * 4);
-            IntBuffer intBuffer = byteBuffer.asIntBuffer();
-            intBuffer.put(secretIntArray);
-            byte[] secretByteArray = byteBuffer.array();
-            KeyStore keyStore = KeyStore.getInstance(ANDROID_KEY_STORE);
-            keyStore.load(null);
-            SecretKey secretKey = (SecretKey) keyStore.getKey(keyName, null);
-            Cipher cipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/" +
-                    KeyProperties.BLOCK_MODE_CBC + "/" + KeyProperties.ENCRYPTION_PADDING_PKCS7);
-
-            // Try encrypting something, it will only work if the user authenticated within
-            // the last AUTHENTICATION_DURATION_SECONDS seconds.
-            cipher.init(Cipher.ENCRYPT_MODE, secretKey);
-            cipher.doFinal(secretByteArray);
-
-            // If the user has recently authenticated, you will reach here.
-            return true;
-        } catch (BadPaddingException | IllegalBlockSizeException | KeyStoreException |
-                CertificateException | UnrecoverableKeyException | IOException
-                | NoSuchPaddingException | NoSuchAlgorithmException | InvalidKeyException e) {
-            return false;
-        }
-    }
 }

+ 1 - 10
src/main/res/values/setup.xml

@@ -20,7 +20,7 @@
     <string name="default_display_name_for_root_folder">Nextcloud</string>
     <string name="user_agent">Mozilla/5.0 (Android) ownCloud-android/%1$s</string>
     <string name="nextcloud_user_agent">Mozilla/5.0 (Android) Nextcloud-android/%1$s</string>
-    
+
     <!-- URLs and flags related -->
     <string name="server_url"></string>
     <bool name="show_server_url_input">true</bool>
@@ -92,15 +92,6 @@
     <!-- Help, imprint and feedback, and other things -->
     <bool name="passcode_enabled">true</bool>
     <bool name="device_credentials_enabled">true</bool>
-    <string name="secret_key_name">Nextcloud</string>
-    <integer-array name="secret_byte_array">
-        <item>1</item>
-        <item>2</item>
-        <item>3</item>
-        <item>4</item>
-        <item>5</item>
-        <item>6</item>
-    </integer-array>
     <bool name="show_hidden_files_enabled">true</bool>
     <bool name="davdroid_integration_enabled">true</bool>
     <bool name="help_enabled">true</bool>