-
-
Notifications
You must be signed in to change notification settings - Fork 27
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
base: master
Are you sure you want to change the base?
ConnectID Foundation #2847
Conversation
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.
…ort test framework
@damagatchi retest this please |
There was a problem hiding this 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
- Java docs for public apis of DB, Network and encryption helpers
- 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); |
There was a problem hiding this comment.
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(); |
There was a problem hiding this comment.
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> |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
reword database
-> table
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); |
There was a problem hiding this comment.
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)
private static KeyStore getKeystore() throws KeyStoreException, CertificateException, | ||
IOException, NoSuchAlgorithmException { | ||
if (keystoreSingleton == null) { | ||
keystoreSingleton = KeyStore.getInstance(KEYSTORE_NAME); | ||
keystoreSingleton.load(null); | ||
} | ||
|
||
return keystoreSingleton; | ||
} |
There was a problem hiding this comment.
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"; |
There was a problem hiding this comment.
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) { |
There was a problem hiding this comment.
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) { |
There was a problem hiding this comment.
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) { |
There was a problem hiding this comment.
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.
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