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

ConnectID Foundation #2847

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open

ConnectID Foundation #2847

wants to merge 4 commits into from

Conversation

OrangeAndGreen
Copy link
Contributor

Summary

Foundational code for ConnectID, primarily consisting of database, network, and encryption code.
This code will support ConnectID when it is integrated into the codebase.
Currently the code in this PR is compiled, but almost completely uncalled.

Product Description

Safety Assurance

The code in this PR is currently not called from anywhere, except:
The EncryptionKeyProvider is created and stored, but never used

Automated test coverage

Unit tests created for the encryption code

Added database models and helper class for storage (with upgrader).
Added network helper class to wrap common functionality for API calls.
Added code to support encryption via a key stored in the Android Keystore.
@OrangeAndGreen
Copy link
Contributor Author

@damagatchi retest this please

Copy link
Contributor

@shubham1g5 shubham1g5 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did a first pass without getting into too much of implementation details, things look mostly good to me overall. A couple things that would be nice to add in this PR

  1. Java docs for public apis of DB, Network and encryption helpers
  2. There are a couple places with LEGACY.. comments, it would be nice to add info on when in future we think those legacy pathways can be eliminated. (or atleast what CC version does that legacy pathway tie to)

super.onConfigurationChanged(newConfig);
LocalePreferences.saveDeviceLocale(newConfig.locale);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why was this removed ?

@@ -544,7 +548,7 @@ public void initializeAppResources(CommCareApp app) {
} catch (Exception e) {
Log.i("FAILURE", "Problem with loading");
Log.i("FAILURE", "E: " + e.getMessage());
e.printStackTrace();
// e.printStackTrace();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove ?

@@ -916,7 +920,7 @@ public static boolean areAutomatedActionsInvalid() {

/**
* Whether the current login is a "demo" mode login.
*
* <p>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lint

@Table(ConnectAppRecord.STORAGE_KEY)
public class ConnectAppRecord extends Persisted implements Serializable {
/**
* Name of database that stores app info for Connect jobs
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reword database -> table

Comment on lines +60 to +64
record.jobId = jobId;
record.date = json.has(META_DATE) ? ConnectNetworkHelper.parseDate(json.getString(META_DATE)) : new Date();
record.score = json.has(META_SCORE) ? json.getInt(META_SCORE) : -1;
record.passingScore = json.has(META_PASSING_SCORE) ? json.getInt(META_PASSING_SCORE) : -1;
record.passed = json.has(META_PASSED) && json.getBoolean(META_PASSED);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for this and rest of the api response parsing, I think we should error out if any of the mandatory fields are not present or in the wrong format (date here) . Otherwise we will bury api response errors until there is an error in user workflow and these errors would be much harder to know/surface/debug in that case. Our tolerance policy in case of api data errors should be zero tolerance and we should crash out the app in such cases. (This will need proper testing before deploy though)

Comment on lines +47 to +55
private static KeyStore getKeystore() throws KeyStoreException, CertificateException,
IOException, NoSuchAlgorithmException {
if (keystoreSingleton == null) {
keystoreSingleton = KeyStore.getInstance(KEYSTORE_NAME);
keystoreSingleton.load(null);
}

return keystoreSingleton;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Think this needs to be threadsafe, a clever way to do it would be to have the singleton reference in a inner class (From Chatgpt - The inner class is loaded only when it's referenced, and since class loading is thread-safe in Java, it guarantees that the instance is created lazily and in a thread-safe manner)

public class Singleton {
    // Private constructor prevents instantiation from other classes
    private Singleton() {}

    // The inner static class responsible for holding the singleton instance
    private static class SingletonHelper {
        // The final static instance, will be initialized when the class is loaded
        private static final Singleton INSTANCE = new Singleton();
    }

    // Public method to access the instance
    public static Singleton getInstance() {
        return SingletonHelper.INSTANCE;
    }
}

*/
public class EncryptionKeyProvider {
private static final String KEYSTORE_NAME = "AndroidKeyStore";
private static final String SECRET_NAME = "secret";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would be nice to have a more descriptive name here - "cc_encryption_key` , but would not do so if it means adding more code to be backward compatible.

if (existingKey instanceof KeyStore.SecretKeyEntry entry) {
return new EncryptionKeyAndTransform(entry.getSecretKey(), getTransformationString(false));
}
if (existingKey instanceof KeyStore.PrivateKeyEntry entry) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lint: if -> else if

}

@SuppressLint("InlinedApi") //Suppressing since we check the API version elsewhere
public static String getTransformationString(boolean useRsa) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: maybe pass the encryption type here directly instead if useRsa (aes vs rsa)


byte[] result = new byte[PASSPHRASE_LENGTH];

while (true) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any idea what's the average number of iterations it will take to arrive at a passphrase that doesn't contain zero ? Mostly thinking if it can result into a near infinite loop.

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

Successfully merging this pull request may close these issues.

2 participants