Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

exception appears during reinitializing Preferences #13

Closed
balamyt opened this issue Jul 14, 2017 · 10 comments
Closed

exception appears during reinitializing Preferences #13

balamyt opened this issue Jul 14, 2017 · 10 comments
Assignees

Comments

@balamyt
Copy link

balamyt commented Jul 14, 2017

in build.gradle:
implementation 'com.github.iamironz:binaryprefs:0.9.9'

сreate the settings as follows

return new BinaryPreferencesBuilder(MainApplication.getInstance())
            .name(BuildConfig.PREFERENCE_FOLDER)
            .encryption(customEncryptor)
            .registerPersistable(MyEntity.KEY, MyEntity.class)
            .build();//crash is here

entity class

public final class MyEntity implements Persistable, Parcelable {

   private int mId;
   private String mSource;
   private long mLastModification;
   private int mRating;


   public MyEntity(int id, String source, long lastModification, int rating) {
      mId = id;
      mSource = source;
      mLastModification = lastModification;
      mRating = rating;
   }

   //...

   @Override
   public void writeExternal(DataOutput out) {
      out.writeInt(mId);
      out.writeString(mSource);
      out.writeLong(mLastModification);
      out.writeInt(mRating);
   }

   @Override
   public void readExternal(DataInput in) {
      mId = in.readInt();
      mSource = in.readString();
      mLastModification = in.readLong();
      mRating = in.readInt();
   }

   @Override
   public Persistable deepClone() {
      return new MyEntity(mId, mSource, mLastModification, mRating);
   }

   //...
}

When first created Preference it's all right. But if called

mPreferences.edit().putPersistable(key, myEntityInstance).commit();

and then app is killed and removed from recents screen then during the next initialization appears exception:

com.ironz.binaryprefs.exception.FileOperationException: java.util.concurrent.ExecutionException: java.lang.ArrayIndexOutOfBoundsException: length=0; index=0
at com.ironz.binaryprefs.task.Completable.completeBlockingUnsafe(Completable.java:44)
at com.ironz.binaryprefs.BinaryPreferences.fetchCache(BinaryPreferences.java:64)
at com.ironz.binaryprefs.BinaryPreferences.(BinaryPreferences.java:43)
at com.ironz.binaryprefs.BinaryPreferencesBuilder.build(BinaryPreferencesBuilder.java:88)
at by.klepcha.app.dagger.ActivityModule.providePreferences(ActivityModule.java:53)
...
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:703)
Caused by: java.util.concurrent.ExecutionException: java.lang.ArrayIndexOutOfBoundsException: length=0; index=0
at java.util.concurrent.FutureTask.report(FutureTask.java:93)
at java.util.concurrent.FutureTask.get(FutureTask.java:163)
at com.ironz.binaryprefs.task.Completable.completeBlockingUnsafe(Completable.java:42)
at com.ironz.binaryprefs.BinaryPreferences.fetchCache(BinaryPreferences.java:64) 
at com.ironz.binaryprefs.BinaryPreferences.(BinaryPreferences.java:43) 
at com.ironz.binaryprefs.BinaryPreferencesBuilder.build(BinaryPreferencesBuilder.java:88) 
at by.klepcha.app.dagger.ActivityModule.providePreferences(ActivityModule.java:53) 
...
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:703) 
Caused by: java.lang.ArrayIndexOutOfBoundsException: length=0; index=0
at com.ironz.binaryprefs.serialization.SerializerFactory.deserialize(SerializerFactory.java:54)
at com.ironz.binaryprefs.BinaryPreferences$1.run(BinaryPreferences.java:59)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:422)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:818)

@iamironz iamironz self-assigned this Jul 14, 2017
@iamironz
Copy link
Contributor

iamironz commented Jul 14, 2017

Hi.
Thanks for issue submitting.
I will investigate this as soon as possible.

Regards.

@iamironz
Copy link
Contributor

@balamyt I see that you has no have default constructor for MyEntity class. You actually don't?

@iamironz
Copy link
Contributor

iamironz commented Jul 14, 2017

Also your customEncryptor#encrypt or recrypt field's methods implementation returns correct encrypted result or byte[0] ?

@iamironz
Copy link
Contributor

iamironz commented Jul 14, 2017

This usually happens if you provide empty byte array into FileAdapter for saving.

@iamironz
Copy link
Contributor

@balamyt
Copy link
Author

balamyt commented Jul 14, 2017

I see that you has no have default constructor for MyEntity class. You actually don't?
Yes, I have not default constructor.

my customEncryptor#encrypt:

   @Override
   public byte[] encrypt(byte[] bytes) {
      if (!hasAlias()) {
         throw createExceptionForDevelopment("set aliases to keystore before encrypt");
      }

      try {
         KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry) mKeyStore.getEntry(mAlias, null);
         RSAPublicKey publicKey = (RSAPublicKey) privateKeyEntry.getCertificate().getPublicKey();

         Cipher inCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", "AndroidOpenSSL");
         inCipher.init(Cipher.ENCRYPT_MODE, publicKey);

         return encrypt(bytes, inCipher);

      } catch (NoSuchAlgorithmException | UnrecoverableEntryException | KeyStoreException | NoSuchProviderException e) {
         throw createExceptionForUser("in encrypt() something wrong at process with encryption", e, e.getLocalizedMessage());
      } catch (NoSuchPaddingException | InvalidKeyException e) {
         throw createExceptionForDevelopment("need check to correct alias before");
      }
   }

   private byte[] encrypt(byte[] bytes, Cipher inCipher) throws AppKeystoreException {
      ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
      CipherOutputStream cipherOutputStream = new CipherOutputStream(outputStream, inCipher);
      try {
         cipherOutputStream.write(bytes);
         return outputStream.toByteArray();
      } catch (IOException e) {
         throw createExceptionForUser("in encrypt() something wrong at process with cipherOutputStream", e, e.getLocalizedMessage());
      } finally {
         CloseableUtils.close(cipherOutputStream);
      }
   }

@iamironz
Copy link
Contributor

iamironz commented Jul 14, 2017

@balamyt try create an unit test which encrypts and decrypts non-empty byte[] value with your encryption.

@iamironz
Copy link
Contributor

iamironz commented Jul 14, 2017

Also please note that you should have default constructor because during initialization it will be called.

@balamyt
Copy link
Author

balamyt commented Jul 14, 2017

Thank!!
It's all right!
The problem was my encryption implementation.

@iamironz
Copy link
Contributor

iamironz commented Jul 14, 2017

Also i've added two stages byte array length checking:

iamironz@bf0ef9d
iamironz@53678f7

This checks will be in 1.0.0-ALPHA1 release.

Regards.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants