-
-
Notifications
You must be signed in to change notification settings - Fork 45
Master to connect #2979
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
Master to connect #2979
Conversation
broke the database helper class in small classes
…e process if necessary
…ty loading phases
…entially be associated with more than one case lists in the app
In AppCompat 1.4+, ActivityController.visible() triggers a layout pass which is triggering OnGlobalLayoutListener().onGlobalLayout() and causing the DemoUserRestoreTest.demoUserRestoreAndUpdateTest() unit test to fail
Expires entity cache for related cases
Cache and Lazy-Load Modifications
Remove media permissions
Address minor UI feedback
Fix Case detail tab title
…ficient-permission Handle failed logins due to insufficient permission
…plane-mode Fix location capture in Airplane mode
…ncies-during-jcenter-sunset Remove directly bundled libraries
📝 WalkthroughWalkthroughThis pull request encompasses a wide spectrum of changes spanning documentation, Android configuration, code refactoring, and new feature additions. The pull request template has been reorganized to enhance clarity, with sections renamed and new prompts added for safety, technical details, and QA planning. In the AndroidManifest and related resources, several permissions have been removed while new services and string entries have been introduced to improve the user interface and feedback mechanisms. The build configuration now includes updated Maven repositories and dependency modifications. Numerous Java and Kotlin classes have been extended with new methods and variables to support improved entity caching, encryption key management, and API networking (including new API client, endpoint, and service classes). There are new database models and upgraders for Connect job records, alongside expanded test coverage and adjustments to layout and widget functionality. In summary, the changes aim to streamline configuration, enhance security and encryption processes, optimize caching workflow, and improve overall code structure. Sequence Diagram(s)sequenceDiagram
participant DA as DataPullTask
participant CA as CommCareApplication
participant WM as WorkManager
participant PR as EntityCacheInvalidationWorker
participant PC as PrimeEntityCacheHelper
participant CS as CommCareEntityStorageCache
DA->>CA: scheduleEntityCacheInvalidation()
CA->>WM: Enqueue EntityCacheInvalidationWorker
WM->>PR: Execute doWork()
PR->>PC: Invoke primeEntityCache()
PC->>CS: Process shallow records for cache invalidation
Possibly related PRs
Suggested reviewers
✨ Finishing Touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
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.
Actionable comments posted: 19
🧹 Nitpick comments (80)
app/src/org/commcare/android/database/connect/models/ConnectLinkedAppRecordV3.java (2)
64-70: Consider token expiration checking logicThe class provides getters for the HQ token and its expiration date, but doesn't include logic to determine if the token has expired. Consider adding a helper method like
isTokenExpired()that compares the expiration date with the current date to simplify token validity checks where this class is used.+ public boolean isTokenExpired() { + return new Date().after(hqTokenExpiration); + }
15-71: Consider implementing equals() and hashCode()If instances of this class will be used in collections like HashSet or as keys in HashMap, implementing equals() and hashCode() would be beneficial to ensure proper object comparison and hashing behavior.
app/src/org/commcare/android/database/connect/models/ConnectLinkedAppRecordV9.java (1)
12-19: Minor documentation issue with misplaced @return tagThe JavaDoc contains an
@returntag at line 19, but this is within the class documentation rather than a method documentation block. This tag is typically used to document the return value of methods, not classes./** * Migrates a V8 record to V9 format. * New in V9: * - Added usingLocalPassphrase field * - Changed link offer date handling * - * @return A new V9 record with migrated data */app/src/org/commcare/android/database/connect/models/ConnectLinkedAppRecordV8.java (1)
89-91: Consider adding setters for boolean flags.The class provides getters for boolean flags like
connectIdLinkedbut no corresponding setters. If these values need to be modified after object creation, consider adding setters.+ public void setConnectIdLinked(boolean connectIdLinked) { + this.connectIdLinked = connectIdLinked; + }app/src/org/commcare/android/database/connect/models/ConnectJobPaymentRecordV3.java (4)
4-9: Unused imports could be removed.Several imports are not used in this class:
- ConnectNetworkHelper (line 4)
- JSONException and JSONObject (lines 8-9)
- ParseException (line 12)
- Locale (line 14)
Consider cleaning up these imports to maintain code clarity.
Also applies to: 12-14
16-21: Class documentation should be enhanced.The class has limited documentation. While the STORAGE_KEY constant is documented, the class itself lacks documentation explaining its purpose, relationship to previous versions (V1, V2), and how it's used within the Connect job payment system.
@Table(ConnectJobPaymentRecordV3.STORAGE_KEY) +/** + * Model class for storing Connect job payment records in the database. + * This is version 3 of the payment record model, enhancing the previous versions + * with improved structure and storage capabilities. + */ public class ConnectJobPaymentRecordV3 extends Persisted implements Serializable { /** * Name of database that stores app info for Connect jobs */ public static final String STORAGE_KEY = "connect_payments";
37-38: Class lacks initialization mechanism.The class only has a default constructor without any parameter-based constructor or setter methods. Without these, it's unclear how instances of this class are populated with data.
Consider adding a parameterized constructor or builder pattern to ensure proper initialization of all fields.
public ConnectJobPaymentRecordV3() { } + +/** + * Constructor with all required fields. + * + * @param jobId The ID of the job this payment belongs to + * @param date The date when payment was made + * @param amount The payment amount as a string + */ +public ConnectJobPaymentRecordV3(int jobId, Date date, String amount) { + this.jobId = jobId; + this.date = date; + this.amount = amount; +}
27-36: Documentation for fields would improve maintainability.Adding documentation for each field would improve code readability and maintainability, especially for future developers working with this model.
@Persisting(1) @MetaField(META_JOB_ID) +/** The ID of the job this payment belongs to */ private int jobId; @Persisting(2) @MetaField(META_DATE) +/** The date when payment was made */ private Date date; @Persisting(3) @MetaField(META_AMOUNT) +/** + * The payment amount as a string. + * Stored as String per system design rather than a numeric type. + */ private String amount;app/src/org/commcare/android/database/connect/models/ConnectUserRecordV5.java (5)
62-66: Fix grammatical errors in Javadoc.There are grammatical issues in the documentation for
registrationPhase./** - * it tells about the current position of registration of user - * Used for smoot registration + * It indicates the current stage of user registration + * Used for smooth registration flow */
68-69: Add documentation for lastPasswordDate field.Missing Javadoc for the
lastPasswordDatefield. Documentation should explain the purpose and usage of this field.+/** + * Timestamp of when the password was last updated. + * Used to track password age and enforce password policies. + */ @Persisting(7) private Date lastPasswordDate;
71-75: Add documentation for connect token fields.The
connectTokenandconnectTokenExpirationfields are missing Javadoc comments.+/** + * Authentication token used for Connect API communications. + * This token is used instead of the password for API calls after login. + */ @Persisting(value = 8, nullable = true) private String connectToken; +/** + * Expiration date for the connectToken. + * Used to determine when a token refresh is needed. + */ @Persisting(value = 9, nullable = true) private Date connectTokenExpiration;
111-113: Add setter method for registration phase.There's no setter method for
registrationPhasedespite it being a state that would need updating during the registration flow.public int getRegistrationPhase() { return registrationPhase; } + +/** + * Updates the registration phase to track progress in the registration flow. + * @param registrationPhase The new registration phase from ConnectConstants + */ +public void setRegistrationPhase(int registrationPhase) { + this.registrationPhase = registrationPhase; +}
119-125: Add token management methods.Consider adding methods to update the connect token and check for token expiration.
public String getConnectToken() { return connectToken; } public Date getConnectTokenExpiration() { return connectTokenExpiration; } + +/** + * Updates the connect token and its expiration date. + * @param newToken The new authentication token + * @param expirationDate The expiration date for the new token + */ +public void updateConnectToken(String newToken, Date expirationDate) { + this.connectToken = newToken; + this.connectTokenExpiration = expirationDate; +} + +/** + * Checks if the current connect token has expired. + * @return true if the token has expired or doesn't exist, false otherwise + */ +public boolean isConnectTokenExpired() { + return connectToken == null || + connectTokenExpiration == null || + connectTokenExpiration.before(new Date()); +}app/src/org/commcare/engine/cases/CaseUtils.java (5)
3-4: Consolidate or keep static imports.These static imports can improve readability, but sometimes they obscure where the constants come from. Evaluate if it helps or if it would be more consistent to import the classes and reference the constants directly.
83-83: Prefer ArrayList over Vector.
Vectorhas unnecessary synchronization overhead in most cases. Unless concurrency is required, useArrayListfor better performance and clarity.
129-156: Refactor user group fixture approach.The approach to load user group IDs from a fixture is labeled “mega sketch” in the TODO. Consider encapsulating the fixture loading in a dedicated helper with robust error handling. Also, this method can return a
List<String>rather thanVector<String>for modern Java best practices.
164-175: Unify data structure usage.This method returns a
Vector<Integer>but accepts aSet<String>. Consider returning a standard List for better consistency.
188-190: Consider consistent collection usage.
ownersis again aVector<String>. For clarity and consistency, please consider usingList<String>unless concurrency is specifically required.app/src/org/commcare/android/database/connect/models/ConnectPaymentUnitRecord.java (1)
1-100: Consider adding validation and more documentation to this payment record class.The class looks well-structured overall, but there are a few areas that could be improved:
There's no validation for monetary values in the
fromJsonmethod. Consider adding checks to ensure that amounts aren't negative.The class has inconsistent mutability - it provides a setter for
maxTotalbut not for other fields.The class would benefit from more documentation explaining the purpose of each field and any assumptions about data formats (e.g., if monetary values are in cents or other smallest units).
The behavior on parsing exceptions could be better documented.
I see from the retrieved learnings that monetary values are intentionally stored as integers. Consider adding a comment explaining this design decision and how these values should be interpreted (e.g., "stored in cents" or similar).
app/src/org/commcare/connect/network/connectId/ApiClient.java (1)
19-19: Address the TODO comment for API retry logic.There's a TODO comment about implementing retry logic for API call failures, but no implementation yet. Consider adding retry capabilities using Retrofit's built-in mechanisms or a library like
com.github.pwittchen:reactivenetwork.app/src/org/commcare/connect/network/connectId/ApiService.java (3)
1-67: Consider improving response handling and method documentationThis interface properly defines API endpoints using Retrofit annotations, but there are several improvements that could enhance maintainability and robustness:
- Use specific model classes for request/response bodies instead of generic Map<String, String> to improve type safety
- Consider using typed response models instead of generic ResponseBody to make parsing more reliable
- Add Javadoc comments explaining the purpose and parameters of each method
- Ensure method names consistently match their endpoint functions (e.g., validateSecondaryPhone uses recoverOTPSecondary endpoint)
Example for one endpoint with these improvements:
+/** + * API interface for ConnectID authentication and user management + */ public interface ApiService { + /** + * Checks if a phone number is available for registration + * @param phoneNumber The phone number to check + * @return Response indicating availability status + */ @GET(ApiEndPoints.phoneAvailable) - Call<ResponseBody> checkPhoneNumber(@Query("phone_number") String phoneNumber); + Call<PhoneAvailabilityResponse> checkPhoneNumber(@Query("phone_number") String phoneNumber); // Similar improvements for other endpoints...
32-33: Method name does not match endpoint nameThe method name
recoverConfirmOTPSecondaryappropriately reflects its function, but there appears to be a mismatch with the endpoint name. Consider ensuring that method names and endpoint references consistently reflect their purposes.
29-30: Method name inconsistent with endpointThe method name
validateSecondaryPhonedoesn't align with the endpoint namerecoverOTPSecondary, which suggests they serve different purposes. Method names should reflect their actual functionality.app/res/layout/entity_select_layout.xml (1)
79-79: Ensure consistent spacing.There's an extra blank line at line 78 that appears to be unnecessary.
app/unit-tests/src/org/commcare/utils/EncryptionUtilsTest.java (1)
1-50: Well-structured encryption unit testsThe new test class provides good coverage for encryption and decryption functionality:
- Successfully tests basic encryption/decryption flow
- Properly handles error cases with null input and null keys
- Uses appropriate assertions to validate results
One observation: while you're using JUnit 4's expected exception annotation for most tests, you're also importing the assertThrows method (line 11) but not using it. This could be streamlined for consistency.
Consider using a consistent approach for testing exceptions - either use the
@Test(expected=...)annotation pattern throughout or useassertThrowsthroughout, but mixing styles may confuse future developers.app/src/org/commcare/models/database/SqlStorage.java (1)
4-4: Unused import addedThe
android.util.Logimport has been added but is not used in the file. Consider removing it to keep the imports clean.-import android.util.Log;app/src/org/commcare/network/HttpCalloutTask.java (1)
127-129: Clean implementation of permission error handlerThe
doResponseInsufficientRolePermissionmethod follows the established pattern of the class. Consider adding logging or more detailed handling in this method to aid in debugging permission issues.private HttpCalloutOutcomes doResponseInsufficientRolePermission(Response response) { + Logger.log(LogTypes.TYPE_USER, "Server returned insufficient role permission error"); return HttpCalloutOutcomes.InsufficientRolePermission; }app/src/org/commcare/fragments/EntitySubnodeDetailFragment.java (1)
106-109: Added placeholder for progress reportingThe new deliverProgress method implements the EntityLoadingProgressListener interface but currently has no implementation. This is correct as a first step, but consider adding actual progress UI feedback in the future.
Consider implementing visual progress updates to enhance the user experience during data loading:
@Override public void deliverProgress(Integer[] values) { - // nothing to do + if (values.length >= 2 && getActivity() != null) { + // Update a progress indicator with values[0] out of values[1] + ((CommCareActivity)getActivity()).updateProgress(values[0], values[1]); + } }app/src/org/commcare/android/database/connect/models/ConnectLearnModuleSummaryRecord.java (1)
58-68: Consider previous feedback about lastUpdate initialization.Based on previous feedback (from PR #2847), the
lastUpdatefield doesn't need to be initialized in thefromJsonmethod.public static ConnectLearnModuleSummaryRecord fromJson(JSONObject json, int moduleIndex) throws JSONException { ConnectLearnModuleSummaryRecord info = new ConnectLearnModuleSummaryRecord(); info.moduleIndex = moduleIndex; info.slug = json.getString(META_SLUG); info.name = json.getString(META_NAME); info.description = json.getString(META_DESCRIPTION); info.timeEstimate = json.getInt(META_ESTIMATE); - info.lastUpdate = new Date(); return info; }app/src/org/commcare/android/database/connect/models/ConnectJobRecordV7.java (1)
162-164: Potential null handling improvement for paymentAccrued.The paymentAccrued field is handled as a String but parsed as an integer in the getter. Consider using a nullable integer wrapper or providing a default construction value.
public int getPaymentAccrued() { - return paymentAccrued != null && paymentAccrued.length() > 0 ? Integer.parseInt(paymentAccrued) : 0; + try { + return paymentAccrued != null && !paymentAccrued.isEmpty() ? Integer.parseInt(paymentAccrued) : 0; + } catch (NumberFormatException e) { + return 0; + } }app/src/org/commcare/entity/AndroidAsyncNodeEntityFactory.kt (2)
33-42: Exception usage might benefit from more descriptive context.
Consider throwing a custom exception with contextual messaging to facilitate debugging if a non-optimizable detail is passed.
79-93: Timeout handling and exception swallowing.
Cancelling existing prime work with a 30-second timeout is appropriate, but consider making this timeout configurable or logging more details about the work being cancelled.app/src/org/commcare/android/database/connect/models/ConnectJobRecord.java (4)
30-74: Consider using enums for status fields.
Currently, statuses likeSTATUS_AVAILABLE_NEW=1,STATUS_AVAILABLE=2, etc., are defined as static ints. Enums or a dedicated class-based approach might improve readability and reduce magic number usage throughout the code.
75-145: Validate integer parsing forpaymentAccrued.
Although retrieved learnings indicate the field is never null, consider defensive checks to avoid potentialNumberFormatExceptionif corrupted data is encountered.
165-252: JSON parsing logic is extensive and might be better modularized.
The largefromJsonmethod could be split into smaller private methods or use builder patterns for maintainability. Also, re-check boolean logic aroundisActive = !json.optBoolean(META_IS_ACTIVE, true)to confirm correctness.
254-560: Bulk getters and setters appear standard but can become unwieldy.
Consider grouping related fields into smaller data-holding classes to reduce class size and improve code organization.app/src/org/commcare/CommCareApplication.java (2)
359-364: Heap-based tuning withguessLargestSupportedBulkCaseFetchSizeFromHeap.
Ensure that this heuristic is beneficial on all device classes. Consider logging or fallback logic if memory constraints differ significantly across devices.
810-811: Scheduling prime entity cache worker automatically.
Take care that repeated scheduling does not happen unnecessarily (e.g., repeated calls or re-entrant calls). If new calls are frequent, consider deduplicating.app/src/org/commcare/connect/network/SsoToken.java (1)
39-39: Remove unnecessary cast to longThe variable
secondsis already a long, so the cast to long is unnecessary.- expiration.setTime(expiration.getTime() + ((long)seconds * 1000)); + expiration.setTime(expiration.getTime() + (seconds * 1000));app/src/org/commcare/android/database/connect/models/ConnectJobLearningRecord.java (4)
72-74: Add defensive copy to date getterThe current implementation returns the date reference directly, which could allow external code to modify the internal date. Create a defensive copy to maintain encapsulation.
public Date getDate() { - return date; + return date != null ? new Date(date.getTime()) : null; }
76-78: Add defensive copy for date parameter in setterThe current implementation directly assigns the input date to the field, which could lead to unexpected behavior if the caller modifies the date object after setting it.
public void setLastUpdate(Date date) { - lastUpdate = date; + lastUpdate = date != null ? new Date(date.getTime()) : null; }
68-70: Consider adding missing getter methodsThe class has getters only for
moduleIdanddate, but not forjobId,duration, orlastUpdate. Consider adding these getters for consistency and to provide complete access to the model data.+ public int getJobId() { + return jobId; + } + + public String getDuration() { + return duration; + } + + public Date getLastUpdate() { + return lastUpdate != null ? new Date(lastUpdate.getTime()) : null; + }
55-66: Add validation for parsed JSON valuesThe
fromJsonmethod doesn't validate the parsed values from JSON. Consider adding validation to ensure the data integrity.public static ConnectJobLearningRecord fromJson(JSONObject json, int jobId) throws JSONException, ParseException { ConnectJobLearningRecord record = new ConnectJobLearningRecord(); record.lastUpdate = new Date(); record.jobId = jobId; - record.date = DateUtils.parseDateTime(json.getString(META_DATE)); + String dateStr = json.getString(META_DATE); + if (dateStr == null || dateStr.isEmpty()) { + throw new JSONException("Missing or empty date value"); + } + record.date = DateUtils.parseDateTime(dateStr); + record.moduleId = json.getInt(META_MODULE); - record.duration = json.getString(META_DURATION); + String duration = json.getString(META_DURATION); + if (duration == null) { + throw new JSONException("Missing duration value"); + } + record.duration = duration; return record; }app/src/org/commcare/connect/database/ConnectAppDatabaseUtil.java (2)
42-44: Use constant-time comparison for passwordUsing
equals()for password comparison could potentially be vulnerable to timing attacks. Consider using a constant-time comparison method for security-sensitive string comparisons.- } else if (!record.getPassword().equals(passwordOrPin)) { + } else if (!MessageDigest.isEqual(record.getPassword().getBytes(), passwordOrPin.getBytes())) {Don't forget to add the import:
import java.security.MessageDigest;
46-52: Document the conditional updating of workerLinkedThe method comments don't clearly explain why workerLinked is handled differently from other fields. Add a comment to explain the rationale for only setting workerLinked to true but not to false.
record.setConnectIdLinked(connectIdLinked); record.setIsUsingLocalPassphrase(localPassphrase); + // We only set workerLinked to true and never revert it back to false + // to maintain worker linkage history if (workerLinked) { - //If passed in false, we'll leave the setting unchanged record.setWorkerLinked(true); }app/src/org/commcare/android/database/connect/models/ConnectJobAssessmentRecord.java (1)
70-84: Getter and setter methods for record properties.The class provides appropriate getter methods for read-only access to assessment data, and a setter for lastUpdate. However, some getters are missing.
Consider adding missing getter methods for completeness:
+public boolean isPassed() { + return passed; +} + +public int getJobId() { + return jobId; +} + +public Date getLastUpdate() { + return lastUpdate; +}app/src/org/commcare/connect/database/ConnectDatabaseHelper.java (1)
53-84: Ensure passphrase is never logged.
The code safely catches exceptions, but verify that no stack traces in the call chain might reveal sensitive passphrases. For example, confirm that passphrases cannot appear in the exception message or logs.app/src/org/commcare/connect/database/ConnectDatabaseUtils.java (1)
68-81: Improve log message clarity.
The log and exception message “We dont find paraphrase in db” contains minor grammar issues. Consider updating it to “Passphrase not found in DB” or similar for clarity.- CrashUtil.log("We dont find paraphrase in db"); + CrashUtil.log("Passphrase not found in DB"); - throw new RuntimeException("We dont find a record in db to get passphrase"); + throw new RuntimeException("No record in DB to retrieve passphrase");app/src/org/commcare/utils/EncryptionKeyProvider.java (2)
37-47: Minor typographical issue in comments.
“encryptrd” should be “encrypted.” Consider updating the code comment for clarity.- * Key store name that store the encryptrd key + * Key store name that stores the encrypted key
87-103: Consider using OAEP padding for RSA operations.
Here, you use"RSA/ECB/PKCS1Padding", which is traditionally acceptable but not the most secure for modern standards. You could replace it with an OAEP-based transformation (e.g.,"RSA/ECB/OAEPWithSHA1AndMGF1Padding") on devices that support it.- return new EncryptionKeyAndTransform(key, "RSA/ECB/PKCS1Padding"); + return new EncryptionKeyAndTransform(key, "RSA/ECB/OAEPWithSHA1AndMGF1Padding");app/src/org/commcare/android/database/connect/models/ConnectAppRecord.java (1)
33-37: Consider clarifying theisLearningpurpose.
This boolean might benefit from additional documentation or a more descriptive name to help future maintainers understand its role in the application.app/src/org/commcare/tasks/EntityLoaderHelper.kt (1)
70-75: Evaluate naming clarity betweencacheEntities(...)methods.
Both the newly introduced method accepting aTreeReferenceand the existing method accepting a list share the same name but different signatures. If confusion arises, consider renaming or adding clarifying KDoc.app/res/values/strings.xml (1)
394-394: Clarify user flow for updates
Consider making the call to action more explicit so users know precisely how to update.-<string name="recovery_network_outdated" cc:translatable="true">The app is outdated and can no longer communicate with the server. Please update the app on the Google Play Store.</string> +<string name="recovery_network_outdated" cc:translatable="true">The app is outdated and can no longer communicate with the server. Please open the Google Play Store and update CommCare now.</string>app/src/org/commcare/models/database/connect/ConnectDatabaseUpgrader.java (1)
99-157: Reduce repeated code blocks
Most upgrade steps (v2→v3, v3→v4, etc.) repeat column additions and record migrations. Extracting shared logic into a helper method would reduce duplication and lessen the chance of versioning errors.app/src/org/commcare/models/database/connect/DatabaseConnectOpenHelper.java (2)
72-80: Be cautious about DB closure after rekey
Callingdb.close()right after rekeying forces the database handle to be closed. Ensure no further operations need to be done on this same handle after rekey.
126-140: Improve fallback error handling
A second attempt to open the database is sensible. If it fails again, consider logging or surfacing more specific troubleshooting info (e.g., incorrect passphrase, DB corruption).app/src/org/commcare/utils/EncryptionUtils.java (2)
39-82: Consider ensuring consistent and robust seeding of randomness in fallback scenario.
The logic that falls back tonew Random()ifSecureRandominstantiation fails could diminish the overall key strength depending on the system’s entropy. While probably acceptable in low-risk contexts, it is worthwhile to log and track such fallback and/or ensure additional entropy is provided.
146-165: Handle unexpected Base64 decoding failures more gracefully.
These methods throw aBase64DecoderExceptionthat can bubble up. To improve user experience, you might consider additional logging or user-facing messaging if corruption is detected.app/src/org/commcare/connect/network/ConnectNetworkHelper.java (2)
49-63: Encapsulate exception details in PostResult to enhance troubleshooting.
StoringresponseStreamandExceptionis good, but consider adding relevant diagnostics such as request payload or partial response for better debugging in case of server or network failures, so long as no sensitive data is leaked.
416-424: Evaluate user guidance for outdated API error messages.
Currently,showOutdatedApiError()just shows a brief Toast. It could be helpful to direct users to update or contact support if the API is no longer compatible.app/src/org/commcare/models/database/user/models/CommCareEntityStorageCache.java (2)
281-290: Validate the approach of deleting shallow records with their related graph.
processShallowRecords()removes shallow records and their transitive references. Double-check that the referencing relationships are correct (e.g., do we need to re-check foreign keys or handle partial references?).
356-375: Consider lines 356-375 for potential DRY improvements.
You build valid keys similarly to how sort keys are built in the older approach. Consolidating into a helper could reduce duplication and make the code more maintainable.app/src/org/commcare/connect/database/JobStoreManager.java (2)
83-95: Avoid resettinglastUpdatemultiple times.
Settingjob.setLastUpdate(new Date())once in this method and again insidestoreOrUpdateJobcan be redundant. Consider consolidating the timestamp update in one place only.
97-127: Improve performance with a quick lookup for existing jobs.
Checking eachexistingJobvia a loop will scale poorly with large lists. Consider using aMap<Integer, ConnectJobRecord>keyed byjobIdto achieve O(1) lookups instead of O(n).- for (ConnectJobRecord existingJob : existingJobs) { - if (existingJob.getJobId() == job.getJobId()) { - job.setID(existingJob.getID()); - isExisting = true; - break; - } - } + Map<Integer, ConnectJobRecord> existingMap = new HashMap<>(); + for (ConnectJobRecord existingJob : existingJobs) { + existingMap.put(existingJob.getJobId(), existingJob); + } + ConnectJobRecord match = existingMap.get(job.getJobId()); + if (match != null) { + job.setID(match.getID()); + isExisting = true; + }app/src/org/commcare/android/database/connect/models/ConnectJobPaymentRecord.java (1)
127-153: Time-zone awareness for date-based checks.
MethodsallowConfirm()andallowConfirmUndo()rely on the difference in UTC-based timestamps. Depending on how user time zones are handled, cross-date edge cases may cause unexpected results.app/src/org/commcare/android/database/connect/models/ConnectJobRecordV2.java (1)
1-202: Use ofDatein modern codebases may be replaced with newer date/time APIs.
While theseDatefields meet current requirements, consider migrating tojava.timeor storing epoch timestamps if more precise control over time zones or date computations is needed in the future.app/src/org/commcare/android/database/connect/models/ConnectJobDeliveryRecordV2.java (1)
33-59: Consider annotatinglastUpdatewith aMetaFieldif it needs explicit persistence mappings.
All other fields include a corresponding@MetaField, whilelastUpdatedoes not. If it is intentionally omitted from the metadata layer, no action is needed. Otherwise, adding a@MetaFieldannotation can help ensure consistent mapping and potential indexing for queries.@Persisting(9) - private Date lastUpdate; + @MetaField("last_update") + private Date lastUpdate;app/src/org/commcare/tasks/PrimeEntityCacheHelper.kt (1)
90-100: Ensure logging of exceptions for diagnosing cache priming issues.
Though thetry/finallyblock effectively resets state, you might want to add logs in thecatchorfinallyblocks to better trace prime operations—especially if an unexpected runtime exception occurs in the loop.app/src/org/commcare/android/database/connect/models/ConnectJobRecordV4.java (1)
208-237:fromV2migration logic is valid and preserves continuity.
Copying fields fromoldRecordand settingdateClaimed = new Date()ensures that newly migrated records comply with the updated schema. For a more transparent data history, you could consider preserving the old date if it exists or storing the migration timestamp in a separate field, but this is optional.app/src/org/commcare/connect/network/connectId/ApiEndPoints.java (1)
3-27: Ensure consistent naming for endpoint constants.Some constants end with a "URL" suffix, while others do not (e.g.,
registerUser,changePhoneNo). Consider appending a consistent suffix (e.g.,URL) to all constants or removing it from others for better clarity.app/src/org/commcare/android/database/connect/models/ConnectJobDeliveryRecord.java (1)
76-101: Validate null returns in JSON parsing logic.When the JSON parsing fails, the method returns null. If any caller doesn't null-check the returned object, it might introduce a NullPointerException. Consider documenting or asserting that callers handle a possible null return.
app/src/org/commcare/android/database/connect/models/ConnectUserRecord.java (1)
157-160: Align field name “lastPasswordDate” with method “getLastPinDate.”Using
lastPasswordDateto represent the last PIN login date causes confusion. Consider renaming the field or methods (e.g.,lastCredentialDate) for clarity.app/src/org/commcare/connect/database/ConnectJobUtils.java (3)
60-115: Consider splitting 'populateJobs' for readability and performance.
This method populates multiple data structures in a single pass, which is efficient but can become cumbersome. Splitting it into separate helpers (e.g.,populateAppInfo,populateModules,populateTransactions) may improve maintainability and testing.
60-60: AvoidVectorunless thread-safety is required.
Vectoris a synchronized collection. If thread safety is not critical, consider usingArrayListfor better performance.- public static void populateJobs(Context context, Vector<ConnectJobRecord> jobs) { + public static void populateJobs(Context context, List<ConnectJobRecord> jobs) {
105-108: Potential large dataset query.
paymentUnitStorage.getRecordsForValues(...)might return large results when jobId is frequent or if many units exist. Consider pagination or partial retrieval if you expect large data volumes for better scalability.app/src/org/commcare/connect/network/ApiConnectId.java (5)
54-84: Add error-handling or user feedback for non-200 statuses.
linkHqWorker()only logs status code errors but does not notify the user or retry. Consider more robust handling, such as retry logic or user-facing error messages.
115-126: Silent handling of missing FCM token.
makeHeartbeatRequestSync()does nothing if the FCM token is null. Consider logging or raising awareness to ensure connectivity checks are not silently ignored.
128-170: Use consistent asynchronous or synchronous patterns.
retrieveConnectIdTokenSync()is synchronous while other methods (e.g.callApi) are asynchronous. Consider standardizing the approach to avoid confusion and potential concurrency issues.
202-232: Centralize progress dialog handling.
callApishows/dismisses progress dialogs, which can get repetitive across different network calls. Consider a shared wrapper or interceptor for uniform UI feedback and error handling logic.
440-470: Enhance user feedback for errors.
handleApiError()andhandleNetworkError()only log server/network errors. For a better user experience, consider providing immediate user-friendly messages or local notifications of the error context.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (21)
app/res/drawable-ldpi/ic_blue_backward.pngis excluded by!**/*.pngapp/res/drawable-ldpi/ic_blue_forward.pngis excluded by!**/*.pngapp/res/drawable-ldpi/icon_chevron_left_brand.pngis excluded by!**/*.pngapp/res/drawable-ldpi/icon_chevron_right_brand.pngis excluded by!**/*.pngapp/res/drawable-mdpi/ic_blue_backward.pngis excluded by!**/*.pngapp/res/drawable-mdpi/ic_blue_forward.pngis excluded by!**/*.pngapp/res/drawable-mdpi/icon_chevron_left_brand.pngis excluded by!**/*.pngapp/res/drawable-mdpi/icon_chevron_right_brand.pngis excluded by!**/*.pngapp/res/drawable-xhdpi/ic_blue_backward.pngis excluded by!**/*.pngapp/res/drawable-xhdpi/ic_blue_forward.pngis excluded by!**/*.pngapp/res/drawable-xhdpi/icon_chevron_left_brand.pngis excluded by!**/*.pngapp/res/drawable-xhdpi/icon_chevron_right_brand.pngis excluded by!**/*.pngapp/res/drawable-xxhdpi/ic_blue_backward.pngis excluded by!**/*.pngapp/res/drawable-xxhdpi/ic_blue_forward.pngis excluded by!**/*.pngapp/res/drawable/icon_auto_advance_arrow.pngis excluded by!**/*.pngapp/res/drawable/icon_chevron_left_brand.pngis excluded by!**/*.pngapp/res/drawable/icon_chevron_left_primary.pngis excluded by!**/*.pngapp/res/drawable/icon_chevron_right_brand.pngis excluded by!**/*.pngapp/res/drawable/icon_chevron_right_primary.pngis excluded by!**/*.pngapp/res/drawable/icon_new.pngis excluded by!**/*.pngapp/res/drawable/icon_next.pngis excluded by!**/*.png
📒 Files selected for processing (107)
.github/pull_request_template.md(1 hunks)app/AndroidManifest.xml(1 hunks)app/assets/locales/android_translatable_strings.txt(2 hunks)app/build.gradle(5 hunks)app/instrumentation-tests/src/org/commcare/androidTests/BaseTest.kt(0 hunks)app/res/layout/entity_select_layout.xml(2 hunks)app/res/layout/screen_form_entry.xml(2 hunks)app/res/layout/square_button_text.xml(1 hunks)app/res/layout/square_card.xml(2 hunks)app/res/values-w320dp/dimens.xml(1 hunks)app/res/values-w600dp/dimens.xml(1 hunks)app/res/values-w720dp/dimens.xml(1 hunks)app/res/values/dimens.xml(2 hunks)app/res/values/strings.xml(3 hunks)app/src/org/commcare/CommCareApp.java(4 hunks)app/src/org/commcare/CommCareApplication.java(23 hunks)app/src/org/commcare/activities/CommCareSetupActivity.java(3 hunks)app/src/org/commcare/activities/EntitySelectActivity.java(11 hunks)app/src/org/commcare/activities/FormEntryActivity.java(1 hunks)app/src/org/commcare/activities/HomeScreenBaseActivity.java(1 hunks)app/src/org/commcare/activities/RecoveryActivity.java(2 hunks)app/src/org/commcare/activities/StandardHomeActivity.java(0 hunks)app/src/org/commcare/activities/SyncCapableCommCareActivity.java(1 hunks)app/src/org/commcare/adapters/EntityDetailPagerAdapter.java(2 hunks)app/src/org/commcare/android/database/connect/models/ConnectAppRecord.java(1 hunks)app/src/org/commcare/android/database/connect/models/ConnectJobAssessmentRecord.java(1 hunks)app/src/org/commcare/android/database/connect/models/ConnectJobDeliveryRecord.java(1 hunks)app/src/org/commcare/android/database/connect/models/ConnectJobDeliveryRecordV2.java(1 hunks)app/src/org/commcare/android/database/connect/models/ConnectJobLearningRecord.java(1 hunks)app/src/org/commcare/android/database/connect/models/ConnectJobPaymentRecord.java(1 hunks)app/src/org/commcare/android/database/connect/models/ConnectJobPaymentRecordV3.java(1 hunks)app/src/org/commcare/android/database/connect/models/ConnectJobRecord.java(1 hunks)app/src/org/commcare/android/database/connect/models/ConnectJobRecordV2.java(1 hunks)app/src/org/commcare/android/database/connect/models/ConnectJobRecordV4.java(1 hunks)app/src/org/commcare/android/database/connect/models/ConnectJobRecordV7.java(1 hunks)app/src/org/commcare/android/database/connect/models/ConnectLearnModuleSummaryRecord.java(1 hunks)app/src/org/commcare/android/database/connect/models/ConnectLinkedAppRecord.java(1 hunks)app/src/org/commcare/android/database/connect/models/ConnectLinkedAppRecordV3.java(1 hunks)app/src/org/commcare/android/database/connect/models/ConnectLinkedAppRecordV8.java(1 hunks)app/src/org/commcare/android/database/connect/models/ConnectLinkedAppRecordV9.java(1 hunks)app/src/org/commcare/android/database/connect/models/ConnectPaymentUnitRecord.java(1 hunks)app/src/org/commcare/android/database/connect/models/ConnectUserRecord.java(1 hunks)app/src/org/commcare/android/database/connect/models/ConnectUserRecordV5.java(1 hunks)app/src/org/commcare/connect/ConnectConstants.java(1 hunks)app/src/org/commcare/connect/database/ConnectAppDatabaseUtil.java(1 hunks)app/src/org/commcare/connect/database/ConnectDatabaseHelper.java(1 hunks)app/src/org/commcare/connect/database/ConnectDatabaseUtils.java(1 hunks)app/src/org/commcare/connect/database/ConnectJobUtils.java(1 hunks)app/src/org/commcare/connect/database/ConnectUserDatabaseUtil.java(1 hunks)app/src/org/commcare/connect/database/JobStoreManager.java(1 hunks)app/src/org/commcare/connect/network/ApiConnectId.java(1 hunks)app/src/org/commcare/connect/network/ConnectNetworkHelper.java(1 hunks)app/src/org/commcare/connect/network/IApiCallback.java(1 hunks)app/src/org/commcare/connect/network/SsoToken.java(1 hunks)app/src/org/commcare/connect/network/connectId/ApiClient.java(1 hunks)app/src/org/commcare/connect/network/connectId/ApiEndPoints.java(1 hunks)app/src/org/commcare/connect/network/connectId/ApiService.java(1 hunks)app/src/org/commcare/engine/cases/CaseUtils.java(6 hunks)app/src/org/commcare/entity/AndroidAsyncNodeEntityFactory.kt(1 hunks)app/src/org/commcare/fragments/EntitySubnodeDetailFragment.java(3 hunks)app/src/org/commcare/google/services/analytics/FirebaseAnalyticsUtil.java(1 hunks)app/src/org/commcare/heartbeat/HeartbeatRequester.java(2 hunks)app/src/org/commcare/location/CommCareLocationControllerFactory.kt(3 hunks)app/src/org/commcare/mediadownload/MissingMediaDownloadHelper.kt(3 hunks)app/src/org/commcare/models/database/SqlStorage.java(2 hunks)app/src/org/commcare/models/database/connect/ConnectDatabaseUpgrader.java(1 hunks)app/src/org/commcare/models/database/connect/DatabaseConnectOpenHelper.java(1 hunks)app/src/org/commcare/models/database/user/DatabaseUserOpenHelper.java(1 hunks)app/src/org/commcare/models/database/user/UserDatabaseUpgrader.java(2 hunks)app/src/org/commcare/models/database/user/models/CommCareEntityStorageCache.java(11 hunks)app/src/org/commcare/network/HttpCalloutTask.java(3 hunks)app/src/org/commcare/preferences/ServerUrls.java(2 hunks)app/src/org/commcare/tasks/ConnectionDiagnosticTask.java(2 hunks)app/src/org/commcare/tasks/DataPullTask.java(2 hunks)app/src/org/commcare/tasks/EntityCacheInvalidationWorker.kt(1 hunks)app/src/org/commcare/tasks/EntityLoaderHelper.kt(5 hunks)app/src/org/commcare/tasks/EntityLoaderListener.java(1 hunks)app/src/org/commcare/tasks/EntityLoaderTask.java(3 hunks)app/src/org/commcare/tasks/ManageKeyRecordTask.java(1 hunks)app/src/org/commcare/tasks/PrimeEntityCache.kt(1 hunks)app/src/org/commcare/tasks/PrimeEntityCacheHelper.kt(1 hunks)app/src/org/commcare/update/UpdateHelper.java(2 hunks)app/src/org/commcare/utils/ConnectivityStatus.java(1 hunks)app/src/org/commcare/utils/EncryptionKeyAndTransform.java(1 hunks)app/src/org/commcare/utils/EncryptionKeyProvider.java(1 hunks)app/src/org/commcare/utils/EncryptionUtils.java(1 hunks)app/src/org/commcare/utils/Permissions.java(1 hunks)app/src/org/commcare/views/TabbedDetailView.java(1 hunks)app/src/org/commcare/views/notifications/NotificationMessageFactory.java(1 hunks)app/src/org/commcare/views/widgets/ImageWidget.java(1 hunks)app/src/org/commcare/views/widgets/VideoWidget.java(1 hunks)app/src/org/commcare/views/widgets/WidgetUtils.java(2 hunks)app/src/org/commcare/xml/AndroidBulkCaseXmlParser.java(1 hunks)app/src/org/commcare/xml/AndroidCaseXmlParser.java(1 hunks)app/unit-tests/resources/commcare-apps/case_list_lookup/restore.xml(3 hunks)app/unit-tests/resources/commcare-apps/index_and_cache_test/incremental_restore.xml(1 hunks)app/unit-tests/resources/commcare-apps/index_and_cache_test/suite.xml(2 hunks)app/unit-tests/src/org/commcare/CommCareTestApplication.java(6 hunks)app/unit-tests/src/org/commcare/android/tests/DataPullTaskTest.java(3 hunks)app/unit-tests/src/org/commcare/android/tests/DemoUserRestoreTest.java(1 hunks)app/unit-tests/src/org/commcare/android/tests/activities/PostRequestActivityTest.java(1 hunks)app/unit-tests/src/org/commcare/android/tests/activities/UpdateActivityTest.java(1 hunks)app/unit-tests/src/org/commcare/android/tests/caselist/EntityListCacheIndexTest.java(2 hunks)app/unit-tests/src/org/commcare/android/tests/formnav/EndOfFormTest.java(1 hunks)app/unit-tests/src/org/commcare/android/tests/processing/FormStorageTest.java(1 hunks)app/unit-tests/src/org/commcare/utils/EncryptionUtilsTest.java(1 hunks)app/unit-tests/src/org/commcare/utils/MockEncryptionKeyProvider.java(1 hunks)
💤 Files with no reviewable changes (2)
- app/instrumentation-tests/src/org/commcare/androidTests/BaseTest.kt
- app/src/org/commcare/activities/StandardHomeActivity.java
🧰 Additional context used
🧠 Learnings (20)
app/src/org/commcare/android/database/connect/models/ConnectLearnModuleSummaryRecord.java (1)
Learnt from: pm-dimagi
PR: dimagi/commcare-android#2847
File: app/src/org/commcare/android/database/connect/models/ConnectLearnModuleSummaryRecord.java:51-52
Timestamp: 2025-01-27T09:51:02.755Z
Learning: The `lastUpdate` field in `ConnectLearnModuleSummaryRecord` does not need to be initialized in the `fromJson` method.
app/src/org/commcare/android/database/connect/models/ConnectJobPaymentRecordV3.java (3)
Learnt from: pm-dimagi
PR: dimagi/commcare-android#2847
File: app/src/org/commcare/android/database/connect/models/ConnectJobPaymentRecordV3.java:39-43
Timestamp: 2025-01-27T09:44:31.082Z
Learning: In ConnectJobPaymentRecordV3 and related payment record classes, the amount field is intentionally stored as a String type rather than a numeric type like BigDecimal.
Learnt from: pm-dimagi
PR: dimagi/commcare-android#2847
File: app/src/org/commcare/android/database/connect/models/ConnectJobRecordV4.java:123-133
Timestamp: 2025-01-26T18:57:52.381Z
Learning: In ConnectJobRecord and related classes, paymentAccrued is guaranteed to be a small integer value that will not overflow and does not need decimal/floating point support.
Learnt from: pm-dimagi
PR: dimagi/commcare-android#2847
File: app/src/org/commcare/android/database/connect/models/ConnectJobRecordV2.java:120-121
Timestamp: 2025-01-26T19:02:16.066Z
Learning: The date fields (projectEndDate, lastUpdate, lastLearnUpdate, lastDeliveryUpdate) in ConnectJobRecordV2 and its newer versions are guaranteed to be non-null through the application's initialization logic and data flow. The newer version (ConnectJobRecord) explicitly initializes these in the constructor, while V2 maintains this guarantee through database upgrades and JSON parsing.
app/src/org/commcare/android/database/connect/models/ConnectJobRecord.java (5)
Learnt from: pm-dimagi
PR: dimagi/commcare-android#2847
File: app/src/org/commcare/android/database/connect/models/ConnectJobRecordV2.java:120-121
Timestamp: 2025-01-26T19:02:16.066Z
Learning: The date fields (projectEndDate, lastUpdate, lastLearnUpdate, lastDeliveryUpdate) in ConnectJobRecordV2 and its newer versions are guaranteed to be non-null through the application's initialization logic and data flow. The newer version (ConnectJobRecord) explicitly initializes these in the constructor, while V2 maintains this guarantee through database upgrades and JSON parsing.
Learnt from: pm-dimagi
PR: dimagi/commcare-android#2847
File: app/src/org/commcare/android/database/connect/models/ConnectJobRecordV4.java:123-133
Timestamp: 2025-01-26T18:57:52.381Z
Learning: In ConnectJobRecord and related classes, paymentAccrued is guaranteed to be a small integer value that will not overflow and does not need decimal/floating point support.
Learnt from: pm-dimagi
PR: dimagi/commcare-android#2847
File: app/src/org/commcare/android/database/connect/models/ConnectJobDeliveryRecord.java:86-93
Timestamp: 2025-01-27T09:08:32.722Z
Learning: The JSON fields (status, unitName, slug, entityId, entityName, reason) in ConnectJobDeliveryRecord's fromJson method are guaranteed to be non-null through the application's data contract, except for the 'id' field which is explicitly checked.
Learnt from: pm-dimagi
PR: dimagi/commcare-android#2847
File: app/src/org/commcare/android/database/connect/models/ConnectJobRecordV2.java:120-121
Timestamp: 2025-01-26T19:02:16.066Z
Learning: The date fields in ConnectJobRecordV2 (projectEndDate, lastUpdate, lastLearnUpdate, lastDeliveryUpdate) are guaranteed to be non-null as part of the core database model design, despite not having explicit initialization in the constructor.
Learnt from: pm-dimagi
PR: dimagi/commcare-android#2847
File: app/src/org/commcare/android/database/connect/models/ConnectJobRecordV2.java:120-121
Timestamp: 2025-01-26T19:02:16.066Z
Learning: The date fields (projectEndDate, lastUpdate, lastLearnUpdate, lastDeliveryUpdate) in ConnectJobRecordV2 are guaranteed to be non-null.
app/src/org/commcare/android/database/connect/models/ConnectJobLearningRecord.java (3)
Learnt from: pm-dimagi
PR: dimagi/commcare-android#2847
File: app/src/org/commcare/android/database/connect/models/ConnectJobRecordV2.java:120-121
Timestamp: 2025-01-26T19:02:16.066Z
Learning: The date fields (projectEndDate, lastUpdate, lastLearnUpdate, lastDeliveryUpdate) in ConnectJobRecordV2 and its newer versions are guaranteed to be non-null through the application's initialization logic and data flow. The newer version (ConnectJobRecord) explicitly initializes these in the constructor, while V2 maintains this guarantee through database upgrades and JSON parsing.
Learnt from: pm-dimagi
PR: dimagi/commcare-android#2847
File: app/src/org/commcare/android/database/connect/models/ConnectJobRecordV2.java:120-121
Timestamp: 2025-01-26T19:02:16.066Z
Learning: The date fields (projectEndDate, lastUpdate, lastLearnUpdate, lastDeliveryUpdate) in ConnectJobRecordV2 are guaranteed to be non-null.
Learnt from: pm-dimagi
PR: dimagi/commcare-android#2847
File: app/src/org/commcare/android/database/connect/models/ConnectJobRecordV2.java:120-121
Timestamp: 2025-01-26T19:02:16.066Z
Learning: The date fields in ConnectJobRecordV2 (projectEndDate, lastUpdate, lastLearnUpdate, lastDeliveryUpdate) are guaranteed to be non-null as part of the core database model design, despite not having explicit initialization in the constructor.
app/src/org/commcare/android/database/connect/models/ConnectLinkedAppRecordV3.java (5)
Learnt from: pm-dimagi
PR: dimagi/commcare-android#2847
File: app/src/org/commcare/android/database/connect/models/ConnectLinkedAppRecordV3.java:1-68
Timestamp: 2025-01-23T21:38:17.427Z
Learning: The versioned database model classes (e.g., ConnectLinkedAppRecordV3) intentionally maintain their original design patterns, including their security implementation, to preserve backward compatibility.
Learnt from: pm-dimagi
PR: dimagi/commcare-android#2847
File: app/src/org/commcare/android/database/connect/models/ConnectLinkedAppRecordV3.java:44-68
Timestamp: 2025-01-23T21:38:24.443Z
Learning: The ConnectLinkedAppRecord classes are intentionally designed with simple getters/setters without additional validation or defensive copies.
Learnt from: pm-dimagi
PR: dimagi/commcare-android#2847
File: app/src/org/commcare/android/database/connect/models/ConnectLinkedAppRecordV3.java:25-39
Timestamp: 2025-01-23T21:38:38.376Z
Learning: The password field in ConnectLinkedAppRecordV3 is intentionally stored without encryption as per the team's design decision.
Learnt from: pm-dimagi
PR: dimagi/commcare-android#2847
File: app/src/org/commcare/android/database/connect/models/ConnectLinkedAppRecordV8.java:107-107
Timestamp: 2025-01-28T08:41:32.380Z
Learning: When upgrading from ConnectLinkedAppRecordV3 to ConnectLinkedAppRecordV8, the connectIdLinked field is intentionally set to true as part of the database migration strategy since this field was not available from the server in V3 and is introduced in V8.
Learnt from: pm-dimagi
PR: dimagi/commcare-android#2847
File: app/src/org/commcare/android/database/connect/models/ConnectLinkedAppRecordV9.java:44-44
Timestamp: 2025-01-26T14:33:04.310Z
Learning: The password field in ConnectLinkedAppRecordV9 is intentionally stored in plain text as it is not linked to any important update and doesn't require encryption.
app/src/org/commcare/android/database/connect/models/ConnectJobRecordV7.java (5)
Learnt from: pm-dimagi
PR: dimagi/commcare-android#2847
File: app/src/org/commcare/android/database/connect/models/ConnectJobRecordV7.java:171-173
Timestamp: 2025-01-26T14:29:13.631Z
Learning: When migrating ConnectJobRecord from V4 to V7 using fromV4() method, isActive is intentionally defaulted to true for all migrated records.
Learnt from: pm-dimagi
PR: dimagi/commcare-android#2847
File: app/src/org/commcare/android/database/connect/models/ConnectJobRecordV4.java:123-133
Timestamp: 2025-01-26T18:57:52.381Z
Learning: In ConnectJobRecord and related classes, paymentAccrued is guaranteed to be a small integer value that will not overflow and does not need decimal/floating point support.
Learnt from: pm-dimagi
PR: dimagi/commcare-android#2847
File: app/src/org/commcare/android/database/connect/models/ConnectJobRecordV2.java:120-121
Timestamp: 2025-01-26T19:02:16.066Z
Learning: The date fields (projectEndDate, lastUpdate, lastLearnUpdate, lastDeliveryUpdate) in ConnectJobRecordV2 and its newer versions are guaranteed to be non-null through the application's initialization logic and data flow. The newer version (ConnectJobRecord) explicitly initializes these in the constructor, while V2 maintains this guarantee through database upgrades and JSON parsing.
Learnt from: pm-dimagi
PR: dimagi/commcare-android#2847
File: app/src/org/commcare/android/database/connect/models/ConnectJobRecordV2.java:120-121
Timestamp: 2025-01-26T19:02:16.066Z
Learning: The date fields in ConnectJobRecordV2 (projectEndDate, lastUpdate, lastLearnUpdate, lastDeliveryUpdate) are guaranteed to be non-null as part of the core database model design, despite not having explicit initialization in the constructor.
Learnt from: pm-dimagi
PR: dimagi/commcare-android#2847
File: app/src/org/commcare/android/database/connect/models/ConnectJobRecordV2.java:120-121
Timestamp: 2025-01-26T19:02:16.066Z
Learning: The date fields (projectEndDate, lastUpdate, lastLearnUpdate, lastDeliveryUpdate) in ConnectJobRecordV2 are guaranteed to be non-null.
app/src/org/commcare/android/database/connect/models/ConnectPaymentUnitRecord.java (3)
Learnt from: pm-dimagi
PR: dimagi/commcare-android#2847
File: app/src/org/commcare/android/database/connect/models/ConnectPaymentUnitRecord.java:41-41
Timestamp: 2025-01-27T09:50:31.480Z
Learning: In ConnectPaymentUnitRecord, monetary values (maxTotal, maxDaily, amount) are intentionally stored as integers.
Learnt from: pm-dimagi
PR: dimagi/commcare-android#2847
File: app/src/org/commcare/android/database/connect/models/ConnectJobPaymentRecordV3.java:39-43
Timestamp: 2025-01-27T09:44:31.082Z
Learning: In ConnectJobPaymentRecordV3 and related payment record classes, the amount field is intentionally stored as a String type rather than a numeric type like BigDecimal.
Learnt from: pm-dimagi
PR: dimagi/commcare-android#2847
File: app/src/org/commcare/android/database/connect/models/ConnectJobRecordV4.java:123-133
Timestamp: 2025-01-26T18:57:52.381Z
Learning: In ConnectJobRecord and related classes, paymentAccrued is guaranteed to be a small integer value that will not overflow and does not need decimal/floating point support.
app/src/org/commcare/connect/network/SsoToken.java (1)
Learnt from: pm-dimagi
PR: dimagi/commcare-android#2847
File: app/src/org/commcare/connect/network/SsoToken.java:0-0
Timestamp: 2025-01-23T21:36:19.292Z
Learning: When handling SSO tokens in Java:
1. Always specify UTF-8 encoding when converting bytes to String
2. Handle potential integer overflow in expiration time calculations
3. Validate token format (e.g., JWT structure)
4. Ensure proper resource cleanup using try-finally blocks
app/src/org/commcare/android/database/connect/models/ConnectLinkedAppRecordV9.java (3)
Learnt from: pm-dimagi
PR: dimagi/commcare-android#2847
File: app/src/org/commcare/android/database/connect/models/ConnectLinkedAppRecordV8.java:107-107
Timestamp: 2025-01-28T08:41:32.380Z
Learning: When upgrading from ConnectLinkedAppRecordV3 to ConnectLinkedAppRecordV8, the connectIdLinked field is intentionally set to true as part of the database migration strategy since this field was not available from the server in V3 and is introduced in V8.
Learnt from: pm-dimagi
PR: dimagi/commcare-android#2847
File: app/src/org/commcare/android/database/connect/models/ConnectLinkedAppRecordV9.java:44-44
Timestamp: 2025-01-26T14:33:04.310Z
Learning: The password field in ConnectLinkedAppRecordV9 is intentionally stored in plain text as it is not linked to any important update and doesn't require encryption.
Learnt from: pm-dimagi
PR: dimagi/commcare-android#2847
File: app/src/org/commcare/android/database/connect/models/ConnectLinkedAppRecordV3.java:1-68
Timestamp: 2025-01-23T21:38:17.427Z
Learning: The versioned database model classes (e.g., ConnectLinkedAppRecordV3) intentionally maintain their original design patterns, including their security implementation, to preserve backward compatibility.
app/src/org/commcare/android/database/connect/models/ConnectJobAssessmentRecord.java (1)
Learnt from: pm-dimagi
PR: dimagi/commcare-android#2847
File: app/src/org/commcare/android/database/connect/models/ConnectJobRecordV2.java:120-121
Timestamp: 2025-01-26T19:02:16.066Z
Learning: The date fields (projectEndDate, lastUpdate, lastLearnUpdate, lastDeliveryUpdate) in ConnectJobRecordV2 and its newer versions are guaranteed to be non-null through the application's initialization logic and data flow. The newer version (ConnectJobRecord) explicitly initializes these in the constructor, while V2 maintains this guarantee through database upgrades and JSON parsing.
app/src/org/commcare/android/database/connect/models/ConnectUserRecordV5.java (2)
Learnt from: pm-dimagi
PR: dimagi/commcare-android#2847
File: app/src/org/commcare/android/database/connect/models/ConnectUserRecordV5.java:72-76
Timestamp: 2025-01-26T14:32:09.266Z
Learning: In ConnectUserRecordV5, initializing lastPasswordDate and connectTokenExpiration to new Date() in the constructor is intentional.
Learnt from: OrangeAndGreen
PR: dimagi/commcare-android#2912
File: app/src/org/commcare/android/database/connect/models/ConnectUserRecord.java:66-71
Timestamp: 2025-01-21T17:28:09.007Z
Learning: The ConnectUserRecord class in CommCare Android uses @Persisting annotations with sequential indices for field persistence, and @MetaField annotations for fields that have corresponding META constants. Fields should be documented with Javadoc comments explaining their purpose, format requirements, and relationships with other fields.
app/src/org/commcare/android/database/connect/models/ConnectJobPaymentRecord.java (3)
Learnt from: pm-dimagi
PR: dimagi/commcare-android#2847
File: app/src/org/commcare/android/database/connect/models/ConnectJobPaymentRecordV3.java:39-43
Timestamp: 2025-01-27T09:44:31.082Z
Learning: In ConnectJobPaymentRecordV3 and related payment record classes, the amount field is intentionally stored as a String type rather than a numeric type like BigDecimal.
Learnt from: pm-dimagi
PR: dimagi/commcare-android#2847
File: app/src/org/commcare/android/database/connect/models/ConnectJobRecordV4.java:123-133
Timestamp: 2025-01-26T18:57:52.381Z
Learning: In ConnectJobRecord and related classes, paymentAccrued is guaranteed to be a small integer value that will not overflow and does not need decimal/floating point support.
Learnt from: pm-dimagi
PR: dimagi/commcare-android#2847
File: app/src/org/commcare/android/database/connect/models/ConnectJobRecordV2.java:120-121
Timestamp: 2025-01-26T19:02:16.066Z
Learning: The date fields (projectEndDate, lastUpdate, lastLearnUpdate, lastDeliveryUpdate) in ConnectJobRecordV2 and its newer versions are guaranteed to be non-null through the application's initialization logic and data flow. The newer version (ConnectJobRecord) explicitly initializes these in the constructor, while V2 maintains this guarantee through database upgrades and JSON parsing.
app/src/org/commcare/android/database/connect/models/ConnectJobDeliveryRecord.java (4)
Learnt from: pm-dimagi
PR: dimagi/commcare-android#2847
File: app/src/org/commcare/android/database/connect/models/ConnectJobDeliveryRecord.java:86-93
Timestamp: 2025-01-27T09:08:32.722Z
Learning: The JSON fields (status, unitName, slug, entityId, entityName, reason) in ConnectJobDeliveryRecord's fromJson method are guaranteed to be non-null through the application's data contract, except for the 'id' field which is explicitly checked.
Learnt from: pm-dimagi
PR: dimagi/commcare-android#2847
File: app/src/org/commcare/android/database/connect/models/ConnectJobRecordV2.java:120-121
Timestamp: 2025-01-26T19:02:16.066Z
Learning: The date fields (projectEndDate, lastUpdate, lastLearnUpdate, lastDeliveryUpdate) in ConnectJobRecordV2 and its newer versions are guaranteed to be non-null through the application's initialization logic and data flow. The newer version (ConnectJobRecord) explicitly initializes these in the constructor, while V2 maintains this guarantee through database upgrades and JSON parsing.
Learnt from: pm-dimagi
PR: dimagi/commcare-android#2847
File: app/src/org/commcare/android/database/connect/models/ConnectJobRecordV2.java:120-121
Timestamp: 2025-01-26T19:02:16.066Z
Learning: The date fields in ConnectJobRecordV2 (projectEndDate, lastUpdate, lastLearnUpdate, lastDeliveryUpdate) are guaranteed to be non-null as part of the core database model design, despite not having explicit initialization in the constructor.
Learnt from: pm-dimagi
PR: dimagi/commcare-android#2847
File: app/src/org/commcare/android/database/connect/models/ConnectJobRecordV2.java:120-121
Timestamp: 2025-01-26T19:02:16.066Z
Learning: The date fields (projectEndDate, lastUpdate, lastLearnUpdate, lastDeliveryUpdate) in ConnectJobRecordV2 are guaranteed to be non-null.
app/src/org/commcare/android/database/connect/models/ConnectJobRecordV2.java (4)
Learnt from: pm-dimagi
PR: dimagi/commcare-android#2847
File: app/src/org/commcare/android/database/connect/models/ConnectJobRecordV2.java:120-121
Timestamp: 2025-01-26T19:02:16.066Z
Learning: The date fields (projectEndDate, lastUpdate, lastLearnUpdate, lastDeliveryUpdate) in ConnectJobRecordV2 and its newer versions are guaranteed to be non-null through the application's initialization logic and data flow. The newer version (ConnectJobRecord) explicitly initializes these in the constructor, while V2 maintains this guarantee through database upgrades and JSON parsing.
Learnt from: pm-dimagi
PR: dimagi/commcare-android#2847
File: app/src/org/commcare/android/database/connect/models/ConnectJobRecordV2.java:120-121
Timestamp: 2025-01-26T19:02:16.066Z
Learning: The date fields in ConnectJobRecordV2 (projectEndDate, lastUpdate, lastLearnUpdate, lastDeliveryUpdate) are guaranteed to be non-null as part of the core database model design, despite not having explicit initialization in the constructor.
Learnt from: pm-dimagi
PR: dimagi/commcare-android#2847
File: app/src/org/commcare/android/database/connect/models/ConnectJobRecordV2.java:120-121
Timestamp: 2025-01-26T19:02:16.066Z
Learning: The date fields (projectEndDate, lastUpdate, lastLearnUpdate, lastDeliveryUpdate) in ConnectJobRecordV2 are guaranteed to be non-null.
Learnt from: pm-dimagi
PR: dimagi/commcare-android#2847
File: app/src/org/commcare/android/database/connect/models/ConnectJobRecordV4.java:123-133
Timestamp: 2025-01-26T18:57:52.381Z
Learning: In ConnectJobRecord and related classes, paymentAccrued is guaranteed to be a small integer value that will not overflow and does not need decimal/floating point support.
app/src/org/commcare/android/database/connect/models/ConnectAppRecord.java (1)
Learnt from: pm-dimagi
PR: dimagi/commcare-android#2847
File: app/src/org/commcare/android/database/connect/models/ConnectLinkedAppRecordV3.java:44-68
Timestamp: 2025-01-23T21:38:24.443Z
Learning: The ConnectLinkedAppRecord classes are intentionally designed with simple getters/setters without additional validation or defensive copies.
app/src/org/commcare/android/database/connect/models/ConnectUserRecord.java (3)
Learnt from: OrangeAndGreen
PR: dimagi/commcare-android#2912
File: app/src/org/commcare/android/database/connect/models/ConnectUserRecord.java:66-71
Timestamp: 2025-01-21T17:28:09.007Z
Learning: The ConnectUserRecord class in CommCare Android uses @Persisting annotations with sequential indices for field persistence, and @MetaField annotations for fields that have corresponding META constants. Fields should be documented with Javadoc comments explaining their purpose, format requirements, and relationships with other fields.
Learnt from: pm-dimagi
PR: dimagi/commcare-android#2847
File: app/src/org/commcare/android/database/connect/models/ConnectUserRecordV5.java:72-76
Timestamp: 2025-01-26T14:32:09.266Z
Learning: In ConnectUserRecordV5, initializing lastPasswordDate and connectTokenExpiration to new Date() in the constructor is intentional.
Learnt from: OrangeAndGreen
PR: dimagi/commcare-android#2912
File: app/src/org/commcare/android/database/connect/models/ConnectUserRecord.java:81-89
Timestamp: 2025-01-21T17:27:58.754Z
Learning: In the CommCare Android codebase, use org.jetbrains.annotations.NotNull for null-safety annotations. Empty strings are acceptable for unspecified values, but null values should be prevented using @NotNull.
app/src/org/commcare/android/database/connect/models/ConnectJobRecordV4.java (5)
Learnt from: pm-dimagi
PR: dimagi/commcare-android#2847
File: app/src/org/commcare/android/database/connect/models/ConnectJobRecordV4.java:123-133
Timestamp: 2025-01-26T18:57:52.381Z
Learning: In ConnectJobRecord and related classes, paymentAccrued is guaranteed to be a small integer value that will not overflow and does not need decimal/floating point support.
Learnt from: pm-dimagi
PR: dimagi/commcare-android#2847
File: app/src/org/commcare/android/database/connect/models/ConnectJobRecordV2.java:120-121
Timestamp: 2025-01-26T19:02:16.066Z
Learning: The date fields (projectEndDate, lastUpdate, lastLearnUpdate, lastDeliveryUpdate) in ConnectJobRecordV2 and its newer versions are guaranteed to be non-null through the application's initialization logic and data flow. The newer version (ConnectJobRecord) explicitly initializes these in the constructor, while V2 maintains this guarantee through database upgrades and JSON parsing.
Learnt from: pm-dimagi
PR: dimagi/commcare-android#2847
File: app/src/org/commcare/android/database/connect/models/ConnectJobRecordV7.java:171-173
Timestamp: 2025-01-26T14:29:13.631Z
Learning: When migrating ConnectJobRecord from V4 to V7 using fromV4() method, isActive is intentionally defaulted to true for all migrated records.
Learnt from: pm-dimagi
PR: dimagi/commcare-android#2847
File: app/src/org/commcare/android/database/connect/models/ConnectJobRecordV2.java:120-121
Timestamp: 2025-01-26T19:02:16.066Z
Learning: The date fields in ConnectJobRecordV2 (projectEndDate, lastUpdate, lastLearnUpdate, lastDeliveryUpdate) are guaranteed to be non-null as part of the core database model design, despite not having explicit initialization in the constructor.
Learnt from: pm-dimagi
PR: dimagi/commcare-android#2847
File: app/src/org/commcare/android/database/connect/models/ConnectJobRecordV2.java:120-121
Timestamp: 2025-01-26T19:02:16.066Z
Learning: The date fields (projectEndDate, lastUpdate, lastLearnUpdate, lastDeliveryUpdate) in ConnectJobRecordV2 are guaranteed to be non-null.
app/src/org/commcare/android/database/connect/models/ConnectLinkedAppRecordV8.java (6)
Learnt from: pm-dimagi
PR: dimagi/commcare-android#2847
File: app/src/org/commcare/android/database/connect/models/ConnectLinkedAppRecordV8.java:107-107
Timestamp: 2025-01-28T08:41:32.380Z
Learning: When upgrading from ConnectLinkedAppRecordV3 to ConnectLinkedAppRecordV8, the connectIdLinked field is intentionally set to true as part of the database migration strategy since this field was not available from the server in V3 and is introduced in V8.
Learnt from: pm-dimagi
PR: dimagi/commcare-android#2847
File: app/src/org/commcare/android/database/connect/models/ConnectLinkedAppRecordV3.java:1-68
Timestamp: 2025-01-23T21:38:17.427Z
Learning: The versioned database model classes (e.g., ConnectLinkedAppRecordV3) intentionally maintain their original design patterns, including their security implementation, to preserve backward compatibility.
Learnt from: pm-dimagi
PR: dimagi/commcare-android#2847
File: app/src/org/commcare/android/database/connect/models/ConnectLinkedAppRecordV3.java:44-68
Timestamp: 2025-01-23T21:38:24.443Z
Learning: The ConnectLinkedAppRecord classes are intentionally designed with simple getters/setters without additional validation or defensive copies.
Learnt from: pm-dimagi
PR: dimagi/commcare-android#2847
File: app/src/org/commcare/android/database/connect/models/ConnectLinkedAppRecordV8.java:107-112
Timestamp: 2025-01-27T15:08:44.820Z
Learning: In ConnectLinkedAppRecordV8, linkOfferDate2 field doesn't allow null values in the database, so it must be initialized with a default date even when linkOffered2 is false.
Learnt from: pm-dimagi
PR: dimagi/commcare-android#2847
File: app/src/org/commcare/android/database/connect/models/ConnectLinkedAppRecordV3.java:25-39
Timestamp: 2025-01-23T21:38:38.376Z
Learning: The password field in ConnectLinkedAppRecordV3 is intentionally stored without encryption as per the team's design decision.
Learnt from: pm-dimagi
PR: dimagi/commcare-android#2847
File: app/src/org/commcare/android/database/connect/models/ConnectLinkedAppRecordV9.java:44-44
Timestamp: 2025-01-26T14:33:04.310Z
Learning: The password field in ConnectLinkedAppRecordV9 is intentionally stored in plain text as it is not linked to any important update and doesn't require encryption.
app/src/org/commcare/android/database/connect/models/ConnectJobDeliveryRecordV2.java (4)
Learnt from: pm-dimagi
PR: dimagi/commcare-android#2847
File: app/src/org/commcare/android/database/connect/models/ConnectJobRecordV2.java:120-121
Timestamp: 2025-01-26T19:02:16.066Z
Learning: The date fields (projectEndDate, lastUpdate, lastLearnUpdate, lastDeliveryUpdate) in ConnectJobRecordV2 and its newer versions are guaranteed to be non-null through the application's initialization logic and data flow. The newer version (ConnectJobRecord) explicitly initializes these in the constructor, while V2 maintains this guarantee through database upgrades and JSON parsing.
Learnt from: pm-dimagi
PR: dimagi/commcare-android#2847
File: app/src/org/commcare/android/database/connect/models/ConnectJobRecordV2.java:120-121
Timestamp: 2025-01-26T19:02:16.066Z
Learning: The date fields in ConnectJobRecordV2 (projectEndDate, lastUpdate, lastLearnUpdate, lastDeliveryUpdate) are guaranteed to be non-null as part of the core database model design, despite not having explicit initialization in the constructor.
Learnt from: pm-dimagi
PR: dimagi/commcare-android#2847
File: app/src/org/commcare/android/database/connect/models/ConnectJobRecordV2.java:120-121
Timestamp: 2025-01-26T19:02:16.066Z
Learning: The date fields (projectEndDate, lastUpdate, lastLearnUpdate, lastDeliveryUpdate) in ConnectJobRecordV2 are guaranteed to be non-null.
Learnt from: pm-dimagi
PR: dimagi/commcare-android#2847
File: app/src/org/commcare/android/database/connect/models/ConnectJobDeliveryRecord.java:86-93
Timestamp: 2025-01-27T09:08:32.722Z
Learning: The JSON fields (status, unitName, slug, entityId, entityName, reason) in ConnectJobDeliveryRecord's fromJson method are guaranteed to be non-null through the application's data contract, except for the 'id' field which is explicitly checked.
app/src/org/commcare/android/database/connect/models/ConnectLinkedAppRecord.java (5)
Learnt from: pm-dimagi
PR: dimagi/commcare-android#2847
File: app/src/org/commcare/android/database/connect/models/ConnectLinkedAppRecordV8.java:107-107
Timestamp: 2025-01-28T08:41:32.380Z
Learning: When upgrading from ConnectLinkedAppRecordV3 to ConnectLinkedAppRecordV8, the connectIdLinked field is intentionally set to true as part of the database migration strategy since this field was not available from the server in V3 and is introduced in V8.
Learnt from: pm-dimagi
PR: dimagi/commcare-android#2847
File: app/src/org/commcare/android/database/connect/models/ConnectLinkedAppRecordV3.java:1-68
Timestamp: 2025-01-23T21:38:17.427Z
Learning: The versioned database model classes (e.g., ConnectLinkedAppRecordV3) intentionally maintain their original design patterns, including their security implementation, to preserve backward compatibility.
Learnt from: pm-dimagi
PR: dimagi/commcare-android#2847
File: app/src/org/commcare/android/database/connect/models/ConnectLinkedAppRecordV3.java:44-68
Timestamp: 2025-01-23T21:38:24.443Z
Learning: The ConnectLinkedAppRecord classes are intentionally designed with simple getters/setters without additional validation or defensive copies.
Learnt from: pm-dimagi
PR: dimagi/commcare-android#2847
File: app/src/org/commcare/android/database/connect/models/ConnectLinkedAppRecordV9.java:44-44
Timestamp: 2025-01-26T14:33:04.310Z
Learning: The password field in ConnectLinkedAppRecordV9 is intentionally stored in plain text as it is not linked to any important update and doesn't require encryption.
Learnt from: pm-dimagi
PR: dimagi/commcare-android#2847
File: app/src/org/commcare/android/database/connect/models/ConnectLinkedAppRecordV3.java:25-39
Timestamp: 2025-01-23T21:38:38.376Z
Learning: The password field in ConnectLinkedAppRecordV3 is intentionally stored without encryption as per the team's design decision.
🪛 ast-grep (0.31.1)
app/src/org/commcare/utils/EncryptionKeyProvider.java
[warning] 60-60: Triple DES (3DES or DESede) is considered deprecated. AES is the recommended cipher. Upgrade to use AES.
Context: KeyStore.getInstance(KEYSTORE_NAME)
Note: [CWE-326]: Inadequate Encryption Strength [OWASP A03:2017]: Sensitive Data Exposure [OWASP A02:2021]: Cryptographic Failures [REFERENCES]
- https://find-sec-bugs.github.io/bugs.htm#TDES_USAGE
- https://csrc.nist.gov/News/2017/Update-to-Current-Use-and-Deprecation-of-TDEA
(desede-is-deprecated-java)
[warning] 116-117: Triple DES (3DES or DESede) is considered deprecated. AES is the recommended cipher. Upgrade to use AES.
Context: KeyGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_AES, KEYSTORE_NAME)
Note: [CWE-326]: Inadequate Encryption Strength [OWASP A03:2017]: Sensitive Data Exposure [OWASP A02:2021]: Cryptographic Failures [REFERENCES]
- https://find-sec-bugs.github.io/bugs.htm#TDES_USAGE
- https://csrc.nist.gov/News/2017/Update-to-Current-Use-and-Deprecation-of-TDEA
(desede-is-deprecated-java)
[warning] 127-127: Triple DES (3DES or DESede) is considered deprecated. AES is the recommended cipher. Upgrade to use AES.
Context: KeyPairGenerator.getInstance("RSA", KEYSTORE_NAME)
Note: [CWE-326]: Inadequate Encryption Strength [OWASP A03:2017]: Sensitive Data Exposure [OWASP A02:2021]: Cryptographic Failures [REFERENCES]
- https://find-sec-bugs.github.io/bugs.htm#TDES_USAGE
- https://csrc.nist.gov/News/2017/Update-to-Current-Use-and-Deprecation-of-TDEA
(desede-is-deprecated-java)
[warning] 60-60: Use of AES with ECB mode detected. ECB doesn't provide message confidentiality and is not semantically secure so should not be used. Instead, use a strong, secure cipher: Cipher.getInstance("AES/CBC/PKCS7PADDING"). See https://owasp.org/www-community/Using_the_Java_Cryptographic_Extensions for more information.
Context: KeyStore.getInstance(KEYSTORE_NAME)
Note: [CWE-327]: Use of a Broken or Risky Cryptographic Algorithm [OWASP A03:2017]: Sensitive Data Exposure [OWASP A02:2021]: Cryptographic Failures [REFERENCES]
- https://owasp.org/Top10/A02_2021-Cryptographic_Failures
- https://googleprojectzero.blogspot.com/2022/10/rc4-is-still-considered-harmful.html
(use-of-aes-ecb-java)
[warning] 116-117: Use of AES with ECB mode detected. ECB doesn't provide message confidentiality and is not semantically secure so should not be used. Instead, use a strong, secure cipher: Cipher.getInstance("AES/CBC/PKCS7PADDING"). See https://owasp.org/www-community/Using_the_Java_Cryptographic_Extensions for more information.
Context: KeyGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_AES, KEYSTORE_NAME)
Note: [CWE-327]: Use of a Broken or Risky Cryptographic Algorithm [OWASP A03:2017]: Sensitive Data Exposure [OWASP A02:2021]: Cryptographic Failures [REFERENCES]
- https://owasp.org/Top10/A02_2021-Cryptographic_Failures
- https://googleprojectzero.blogspot.com/2022/10/rc4-is-still-considered-harmful.html
(use-of-aes-ecb-java)
[warning] 127-127: Use of AES with ECB mode detected. ECB doesn't provide message confidentiality and is not semantically secure so should not be used. Instead, use a strong, secure cipher: Cipher.getInstance("AES/CBC/PKCS7PADDING"). See https://owasp.org/www-community/Using_the_Java_Cryptographic_Extensions for more information.
Context: KeyPairGenerator.getInstance("RSA", KEYSTORE_NAME)
Note: [CWE-327]: Use of a Broken or Risky Cryptographic Algorithm [OWASP A03:2017]: Sensitive Data Exposure [OWASP A02:2021]: Cryptographic Failures [REFERENCES]
- https://owasp.org/Top10/A02_2021-Cryptographic_Failures
- https://googleprojectzero.blogspot.com/2022/10/rc4-is-still-considered-harmful.html
(use-of-aes-ecb-java)
🔇 Additional comments (201)
app/src/org/commcare/update/UpdateHelper.java (1)
39-39: Good refactoring to improve code readability and maintainabilityThis change simplifies obtaining the application ID by using a dedicated utility function from
AppUtilsinstead of chaining multiple method calls. This approach centralizes the logic for retrieving the application ID, making the code more maintainable and easier to test.Also applies to: 277-277
app/src/org/commcare/heartbeat/HeartbeatRequester.java (2)
4-4: Good refactoring: Using the static utility methodAdding the import for
getCurrentAppIdfrom AppUtils is a good practice that contributes to code maintainability.
111-111: LGTM: Clean implementation of the utility methodReplacing the direct call to
CommCareApplication.instance().getCurrentApp().getUniqueId()with the static utility methodgetCurrentAppId()improves code readability and maintainability by centralizing this logic. This helps reduce code duplication and provides a consistent way to access the app ID throughout the codebase.app/src/org/commcare/android/database/connect/models/ConnectLinkedAppRecordV3.java (2)
25-39: Note about password storage securityI understand from previous feedback that storing the password field in plain text is an intentional design decision for backward compatibility in these versioned database models. While this approach preserves compatibility, it's worth remembering the security implications of unencrypted password storage.
1-71: LGTM - Implementation follows team's established patternsThe implementation follows the team's established patterns for versioned database models with simple getters/setters without additional validation or defensive copies, which aligns with the design decision to preserve backward compatibility.
app/src/org/commcare/android/database/connect/models/ConnectLinkedAppRecordV9.java (5)
42-44: Password stored in plain text as intendedI note that the password field is stored in plain text. According to the retrieved learning context, this is intentional as "the password field in ConnectLinkedAppRecordV9 is intentionally stored in plain text as it is not linked to any important update and doesn't require encryption."
108-114: Clear approach to link offer date handlingThe implementation of
getLinkOfferDate1()andgetLinkOfferDate2()returns null when the respective offer hasn't been made (based on boolean flags). This is a clean approach that avoids the need for null checks in the stored date fields themselves.
130-133: Well-implemented date migration logicThe migration logic from V8 to V9 correctly preserves link offer dates when they exist, while initializing new dates for offers that weren't made. This maintains data consistency during the migration.
134-135: Good default value with clear comment for backward compatibilitySetting
usingLocalPassphraseto true by default with a clear comment about backward compatibility is a good practice. This ensures existing records will maintain expected behavior when migrated to the new version.
2-139: Overall well-structured database model with clear migration pathThis class is well-organized with proper annotations for database persistence, clear field naming, and a thorough migration method from V8. The code follows the established patterns for versioned database models in the codebase, maintaining backward compatibility as mentioned in the retrieved learning context.
app/src/org/commcare/android/database/connect/models/ConnectLinkedAppRecordV8.java (7)
1-22: Well-structured class declaration with appropriate documentation.The class has clear documentation, properly defines its storage key, and follows CommCare's database model patterns with appropriate annotations.
23-30: LGTM - Clear metadata constant definitions.The metadata constants are well-named and follow a consistent naming pattern, making the code more maintainable.
31-60: Database field declarations are properly annotated.All fields have correct persistence annotations with sequential ordering. Metadata fields are properly linked to their constants.
38-38: Consider encrypting the password field.The password is stored as plain text. While I understand from retrieved learnings that this is intentional in related classes, storing passwords without encryption is generally a security risk.
Is this plain text storage of passwords still the intended approach for this new V8 class?
61-99: Accessor methods follow consistent patterns.The getter methods are appropriately implemented. The date getters (lines 93-99) properly handle the conditional return of dates based on boolean flags.
101-118: Migration strategy from V3 correctly implemented.The
fromV3method correctly maps fields from the older version and sets appropriate defaults for new fields. SettingconnectIdLinkedtotruealigns with the retrieved learning that this field was not available in V3 and is introduced in V8.
115-115: Initializing linkOfferDate2 when linkOffered2 is false is consistent with design.Even though
linkOffered2is set to false, initializinglinkOfferDate2with the current date is necessary since this field doesn't allow null values in the database, as confirmed by retrieved learnings.app/src/org/commcare/android/database/connect/models/ConnectJobPaymentRecordV3.java (2)
35-35: Storing amount as String is intentional per system design.Based on the retrieved learnings, the amount field is intentionally stored as a String rather than a numeric type like BigDecimal, which is consistent with the class design.
16-17:Details
✅ Verification successful
Consider version migration mechanism.
As this is version 3 of the ConnectJobPaymentRecord model, there should be a migration path from older versions. The code doesn't include any static conversion methods (like
fromV2) to facilitate migrations.
🏁 Script executed:
#!/bin/bash # Check if there are migration paths in database upgraders or other files echo "Checking for database upgraders:" fd -t f "DatabaseUpgrader.*\.java" echo echo "Checking for conversion methods in related classes:" rg "fromV3|toV3|convert.*V3" --type java app/src/org/commcare/android/database/connect/Length of output: 943
Migration mechanism confirmed via external conversion methods
After verification, the conversion from ConnectJobPaymentRecordV3 is handled externally. In particular, the static method
public static ConnectJobPaymentRecord fromV3(ConnectJobPaymentRecordV3 oldRecord)in app/src/org/commcare/android/database/connect/models/ConnectJobPaymentRecord.java serves as the migration path from version 3 to the current model. A similar pattern is followed in other parts of the codebase (e.g., ConnectLinkedAppRecordV8).
As such, no additional in-class conversion (like a fromV2 method in ConnectJobPaymentRecordV3) is necessary. Please ensure that this migration strategy is well-documented so future developers can easily follow the intended design.
app/src/org/commcare/android/database/connect/models/ConnectUserRecordV5.java (2)
77-81: The initialization of dates in the constructor is intentional.The initialization of
lastPasswordDateandconnectTokenExpirationtonew Date()is intentional as noted in the retrieved learnings.
22-27: Class follows persistence patterns documented in retrieved learnings.The class uses the
@Tableannotation and follows the sequential indices pattern for@Persistingannotations as mentioned in the retrieved learning.app/AndroidManifest.xml (1)
176-184: Ensure disabled service is correct.The newly introduced service is disabled and not exported. Please verify that this is intentional and doesn't interfere with Google Play Services integration. Also confirm that ignoring the missing class lint is the intended approach so you don’t encounter runtime issues.
Would you like a shell script to search references to this class and ensure it's never dynamically loaded at runtime?
app/src/org/commcare/engine/cases/CaseUtils.java (4)
34-35: Imports for new data structures.These imports appear correct. No concerns.
55-56: Confirm metadata usage.Consider verifying that
INDEX_CASE_IDis never null or empty. If there's a possibility of missing or malformed entries, handle them gracefully to avoid potentialNullPointerException.Do you want me to generate a script to detect any records with missing or invalid case IDs in the database?
87-87: Transaction management looks good.Enclosing the transaction in a try-catch-finally block ensures proper rollback on failure. Nice job!
177-185: Handle possible parse errors.
Integer.parseInt(recordId)can throwNumberFormatExceptionifrecordIdisn’t numeric. Consider verifying inputs or adding graceful error handling.app/src/org/commcare/connect/ConnectConstants.java (1)
1-19: Centralized ConnectID constants look good.Adding a dedicated constants class promotes better maintainability and readability. No issues spotted.
app/build.gradle (3)
74-74: Approval: Updated Simprints library.The Simprints library has been updated to a more recent version, which is a good practice for keeping dependencies current.
86-88: Support for Retrofit network client.These new dependencies support the ApiClient implementation for network communication. This is a good modernization of the networking stack.
25-25:Details
❓ Verification inconclusive
Verify the Liferay repository is necessary.
A new Maven repository URL for Liferay has been added, but it's not clear which dependency requires it.
🏁 Script executed:
#!/bin/bash # Check for dependencies that might reference the Liferay repository grep -r --include="*.gradle" "liferay" .Length of output: 143
Action Required: Confirm the Necessity of the Liferay Repository
The repository declaration in
app/build.gradleis the only instance where "liferay" appears across the Gradle files. There are no direct references to a dependency that explicitly requires artifacts fromhttps://repository.liferay.com/nexus/content/repositories/public/. Please verify if this repository is needed—perhaps for transitive dependencies or future integrations—and consider adding a clarifying comment. If it turns out not to be required, removing it could simplify the configuration.app/src/org/commcare/connect/network/connectId/ApiClient.java (2)
29-38: Well-implemented thread-safe singleton.The double-checked locking pattern is correctly implemented for thread safety when creating the Retrofit instance.
40-67: Good API client configuration with security considerations.The OkHttp client setup includes:
- Appropriate logging levels based on debug/release builds
- Header redaction for sensitive information
- Reasonable timeout values
- Proper content negotiation with version header
This shows good attention to security and performance concerns.
app/unit-tests/src/org/commcare/CommCareTestApplication.java (1)
81-81: Good addition of MockEncryptionKeyProvider for testing.Setting the encryption key provider in the test application enables better isolation and control in test environments.
app/unit-tests/src/org/commcare/android/tests/activities/PostRequestActivityTest.java (1)
70-70: Initializing WorkManager for tests is a good practiceAdding WorkManager initialization ensures that the test environment properly reflects the production environment functionality, especially if the code under test depends on WorkManager.
app/unit-tests/src/org/commcare/android/tests/activities/UpdateActivityTest.java (1)
50-50:Details
✅ Verification successful
Consistent WorkManager initialization for test reliability
This change ensures WorkManager is properly initialized before test execution, maintaining consistency with other test classes. This is especially important for tests that might indirectly rely on WorkManager functionality.
Verify that this initialization is applied consistently across all test classes:
🏁 Script executed:
#!/bin/bash # Find all test setup methods echo "Checking for consistent WorkManager initialization across test classes..." rg -A 2 "@Before.*setup|@Before.*setUp" --type java app/unit-tests/ # Count how many initialize WorkManager echo "Test classes that initialize WorkManager:" rg "initWorkManager\(\)" --type java app/unit-tests/ | wc -lLength of output: 384
Consistent WorkManager Initialization Confirmed
The verification shows that 5 test classes in the repository call
initWorkManager(), which aligns with the intended consistency across tests. The update inUpdateActivityTest.javareflects the same pattern as used in other test classes, ensuring WorkManager is properly initialized before tests run.
- Confirmed through the shell script, all relevant test classes consistently invoke WorkManager initialization.
- The snippet in question is in line with the repository-wide test setup.
app/src/org/commcare/activities/SyncCapableCommCareActivity.java (1)
264-264: Good addition for cache consistencyThis new call ensures entity cache invalidation after form submission, maintaining data consistency between local storage and server state.
app/src/org/commcare/activities/RecoveryActivity.java (2)
20-20: Good addition of LogTypes importRequired for the new network logging functionality - clean import.
180-182: Enhanced network error loggingAdding specific logging for network unavailability will improve diagnostics and troubleshooting capabilities.
app/src/org/commcare/tasks/ManageKeyRecordTask.java (1)
210-213: Good addition of insufficient role permission handlingThis new case properly handles the scenario where a user has insufficient permissions during login, providing clear feedback about the authorization failure.
app/unit-tests/src/org/commcare/android/tests/formnav/EndOfFormTest.java (1)
45-45: Important test initialization updateInitializing WorkManager in the test setup ensures background processing works correctly during test execution, maintaining consistent test behavior.
app/unit-tests/resources/commcare-apps/index_and_cache_test/incremental_restore.xml (1)
1-18: Well-structured OpenRosa test resource added.This new test XML file provides a well-formed sample of an incremental restore payload with appropriate user group and case elements. The structure follows the OpenRosa response format and includes realistic test data that will be useful for testing case processing functionality.
app/unit-tests/src/org/commcare/android/tests/DataPullTaskTest.java (3)
3-6: Import statements reorganized correctly.The imports for AndroidJUnit4 and ApplicationProvider have been properly moved after the package declaration, improving code organization.
16-16: Added junit.Before import for new setUp method.The import for @before annotation has been properly added to support the new test setup method.
45-49: Added proper test initialization for WorkManager.The new setUp method correctly initializes WorkManager before each test runs, which is necessary for tests that may involve background tasks. This follows JUnit best practices by ensuring proper test environment setup.
app/res/layout/square_button_text.xml (1)
29-30: Text size adjusted for better UI consistency.The text size has been reduced from xlarge to large, and the small text size from large to medium. This change appears to be part of a broader effort to standardize text sizes across the application, improving visual consistency.
app/res/layout/square_card.xml (2)
44-45: Text size reduced for better UI consistency.The card_text component's text size has been reduced from xlarge to large, and the small text size from large to medium. This change matches similar adjustments in other layouts, ensuring a consistent text sizing approach throughout the app.
57-57: Subtext size adjusted for better readability.The card_subtext component's text size has been changed from medium to small. This maintains proper visual hierarchy between the main card text and subtext.
app/src/org/commcare/tasks/DataPullTask.java (2)
439-439: Enhancement to cache management after recovery.The addition of
PrimeEntityCacheHelper.schedulePrimeEntityCacheWorker()call ensures that the entity cache is primed after a successful recovery, which will improve user experience by ensuring data is available after system recovery.
454-454: Improved cache invalidation after sync.Adding the cache invalidation scheduling as part of successful sync process ensures that stale entity data won't be used, maintaining data consistency between local storage and newly synced data.
app/src/org/commcare/views/notifications/NotificationMessageFactory.java (1)
63-66: New authentication failure message for insufficient role permissions.The newly added enum constant
Auth_InsufficientRolePermissionproperly follows the existing pattern and provides appropriate documentation. This enhances the application's ability to provide specific feedback when a user doesn't have the necessary role-based permissions to access the CommCare mobile app.app/src/org/commcare/xml/AndroidCaseXmlParser.java (1)
100-100: Method name updated for consistency.The change from
invalidateCachetoinvalidateRecordreflects a more specific action being performed and is likely part of a larger refactoring to improve naming consistency throughout the codebase.app/src/org/commcare/activities/HomeScreenBaseActivity.java (1)
1525-1526: Added network availability logging.This additional logging will help with debugging network connectivity issues during update checks. Proper log messages are essential for troubleshooting in production environments.
app/src/org/commcare/activities/FormEntryActivity.java (1)
352-353: Improved UX: Toast message for cancelled location captureAdding a toast notification when location capture is cancelled provides consistent user feedback with other cancelation scenarios. This helps maintain a coherent user experience.
app/src/org/commcare/views/widgets/VideoWidget.java (1)
68-70: Good refactoring: Using centralized utility method for media intent creationReplacing direct intent construction with
WidgetUtils.createPickMediaIntent()improves code maintainability by centralizing the intent creation logic. This approach makes it easier to maintain consistent behavior across different media types and to adapt to platform changes.app/unit-tests/src/org/commcare/android/tests/DemoUserRestoreTest.java (1)
54-57: Good test infrastructure improvement: Skipping WorkManager in testsAdding the setUp method to skip WorkManager initialization during tests is a good practice that will help avoid potential issues with background tasks interfering with test execution.
app/src/org/commcare/tasks/EntityCacheInvalidationWorker.kt (1)
1-24: Well-implemented coroutine worker for entity cache invalidationThis new EntityCacheInvalidationWorker correctly implements the CoroutineWorker pattern with proper error handling. The worker efficiently processes entity cache invalidation in the background, which should improve app performance.
A few observations:
- Good use of suspend function for the worker implementation
- Proper error logging and result reporting
- Clean separation of concerns by focusing only on cache invalidation
app/res/layout/entity_select_layout.xml (2)
55-59: Well-structured progress container implementation.The addition of a dedicated RelativeLayout to contain the progress indicators provides a clean organization for loading UI elements. This container is properly positioned below the filter dropdown and spans the full width.
68-74: Good enhancement to loading feedback mechanism.Adding the progress_text TextView complements the existing loading spinner, providing users with more context about what's happening during loading operations. The text is properly centered and has appropriate padding.
app/src/org/commcare/connect/network/IApiCallback.java (1)
1-17: Well-designed network callback interface.This interface provides a clean separation of concerns for handling different network request outcomes:
- Success handling with response code and data
- Failure handling with response code and exception
- Network failure handling for connectivity issues
- Specific handling for API version incompatibilities
This approach aligns with best practices for network error handling and promotes consistent error management across the application.
app/src/org/commcare/preferences/ServerUrls.java (2)
9-10: Appropriate imports for URL manipulation.The added imports for URL and MalformedURLException support the new endpoint building functionality.
37-59: Robust endpoint construction with proper error handling.The
buildEndpointmethod is well-implemented with:
- Clear documentation with JavaDoc comments
- Proper validation of input parameters
- Null checks for both the path and key server URL
- Appropriate exception handling for malformed URLs
- Consistent with URL construction best practices
This centralized approach reduces duplication and standardizes URL construction across the application.
app/src/org/commcare/views/TabbedDetailView.java (1)
89-89: Good refactoring to improve separation of concerns.Changing from directly accessing
detail.getDetails()[position].getTitle().getText().evaluate()to usingentityDetailPagerAdapter.getPageTitle(position)properly delegates the responsibility of determining tab titles to the adapter. This improves the separation of concerns and makes the code more maintainable.app/src/org/commcare/activities/CommCareSetupActivity.java (1)
49-49: Good addition of network logging!The new logging statement provides useful diagnostic information when a network connection is unavailable during app installation. This is a good practice for tracking connectivity issues.
Also applies to: 62-62, 780-780
app/res/values-w600dp/dimens.xml (1)
5-7: Font size adjustments improve readabilityThe changes adjust the font size hierarchy by:
- Reducing medium font from 20sp to 18sp
- Increasing large font from 24sp to 25sp
- Increasing xlarge font from 28sp to 30sp
These adjustments create better visual distinction between different text sizes.
app/src/org/commcare/adapters/EntityDetailPagerAdapter.java (1)
62-65: Good implementation of getPageTitle methodThe new method correctly determines the page title based on whether the detail is compound or not, evaluating the appropriate title text in each case. This enhances the adapter's functionality and enables proper labeling in tabbed views.
app/src/org/commcare/google/services/analytics/FirebaseAnalyticsUtil.java (1)
278-278: Method name update for consistencyThe method name has been updated from
getMD5HashAsStringtogetMd5HashAsString, which follows a more consistent naming convention for abbreviations in method names (camelCase rather than uppercase).app/src/org/commcare/views/widgets/ImageWidget.java (1)
141-143: Good refactoring to use a utility methodMoving the intent creation logic to
WidgetUtils.createPickMediaIntent()improves code reusability and maintainability. This change follows good software engineering practices by centralizing common functionality.app/res/values-w720dp/dimens.xml (1)
5-7: Font size adjustment for large screensThe font sizes for large screens (w720dp) have been reduced, creating a more balanced visual hierarchy:
- Small font: 20sp → 18sp
- Medium font: 24sp → 19sp
- Large font: 28sp → 26sp
These changes are part of a wider effort to adjust font sizes throughout the application, which should improve readability and user experience.
app/src/org/commcare/mediadownload/MissingMediaDownloadHelper.kt (1)
6-6: Good refactoring to use centralized utility methodThe changes replace direct calls to
CommCareApplication.instance().currentAppwith the utility methodgetCurrentAppId(). This is a positive change that centralizes app ID access, improving maintainability and making future changes easier to implement.Also applies to: 53-53, 70-70
app/src/org/commcare/xml/AndroidBulkCaseXmlParser.java (1)
86-86: Method name standardizationThe method call has been updated from
invalidateCachestoinvalidateRecords, which appears to be part of a larger effort to standardize method naming across the codebase. This makes the API more consistent and the method name better represents its functionality.app/src/org/commcare/models/database/user/DatabaseUserOpenHelper.java (1)
69-69: Database version incremented for schema updateThe database version has been correctly incremented from 28 to 29 to accommodate the addition of
is_dirtyandis_shallowcolumns to the entity_cache table. The version history comment has been properly updated to document this change.Also applies to: 72-72
app/src/org/commcare/location/CommCareLocationControllerFactory.kt (2)
4-4: Enhanced controller selection to account for airplane modeAdding the airplane mode check improves the location controller selection logic. This prevents the app from attempting to use the Fused Location provider when it wouldn't work properly due to airplane mode being enabled.
Also applies to: 18-18
28-30: Well-implemented airplane mode detection methodThe new
isAirplaneModeOnmethod correctly uses the Android Settings API to check the airplane mode status. The implementation is straightforward and follows Android best practices.app/res/values-w320dp/dimens.xml (1)
4-7: Font size increases might impact layout in some screensThe font size increases across all text categories (small, medium, large, xlarge) will improve text readability, especially for users with visual impairments. However, these larger font sizes might cause layout issues in constrained UI elements or screens with limited space.
Consider verifying how these changes affect layout in screens with tight spacing constraints, particularly for elements using font_size_small and font_size_medium.
app/unit-tests/resources/commcare-apps/case_list_lookup/restore.xml (3)
17-19: Case hierarchy structure added for test dataThe added parent-child relationship between "stan" and "pat" cases enhances the test data to support hierarchical case relationship testing.
33-35: Extended case hierarchy with second parent-child relationshipAdding another parent-child relationship between "ellen" and "stan" creates a three-level case hierarchy (pat → stan → ellen) that will be useful for testing multi-level case relationships.
115-115: Added proper EOF newlineAdded newline at the end of file, ensuring proper XML file formatting.
app/unit-tests/src/org/commcare/utils/MockEncryptionKeyProvider.java (1)
1-33: Well-implemented mock class for encryption testingThis mock encryption key provider implementation is appropriate for testing purposes:
- Good documentation explaining security limitations
- Proper key size (2048 bits) for RSA encryption
- Efficient key pair reuse pattern
- Clear comments indicating not for production use
app/res/layout/screen_form_entry.xml (2)
89-89: Improved layout flexibility with wrap_contentChanging the ProgressBar height from a fixed dimension to
wrap_contentimproves layout flexibility, allowing the progress bar to adjust based on its content and screen density.
100-101: Enhanced padding consistencyUsing a dedicated dimension resource
@dimen/progressbar_vertical_paddingfor the vertical padding is a good practice. This improves consistency across the UI and makes future padding adjustments easier to maintain.app/src/org/commcare/utils/EncryptionKeyAndTransform.java (1)
1-50: Well-designed utility class for encryptionThis new utility class is well-structured with:
- Proper encapsulation of key and transformation data
- Thorough validation in the constructor
- Defensive copying of mutable key objects
- Clear documentation
The validation patterns and error messages are clear and specific, which will help with debugging.
The regex pattern for transformation validation (
"[A-Za-z0-9]+/[A-Za-z0-9]+/[A-Za-z0-9]+Padding") ensures the standard Algorithm/Mode/Padding format is followed.app/src/org/commcare/network/HttpCalloutTask.java (2)
46-46: Added support for handling insufficient permissionsAdding the
InsufficientRolePermissionoutcome to the enum is a good extension to handle 403 Forbidden responses from the server.
85-86: Enhanced HTTP response handling for permission errorsThe addition of a specific handler for 403 responses improves error handling specificity, allowing the application to provide better feedback to users when they lack sufficient permissions.
app/assets/locales/android_translatable_strings.txt (2)
532-534: Added user-friendly messages for permission errorsThese new string entries provide clear, descriptive error messages for insufficient role permissions. The messages follow the established pattern:
- Title: Identifies the issue
- Detail: Explains what happened
- Action: Suggests what the user should do
This maintains consistency with other error messages in the application.
1000-1000: Added feedback message for location capture cancellationThis short, concise message will provide good feedback when a location capture operation is cancelled.
app/src/org/commcare/CommCareApp.java (3)
28-28: Verify new import statements are used by the changes.The new import statements for
PrimeEntityCacheHelperandNotNullannotations appear to be used in the new implementation below.Also applies to: 48-48
81-81: Good implementation of a thread-safe cache helper.The usage of
volatilefor theprimeEntityCacheHelperfield is appropriate for the double-checked locking pattern implemented in the getter method.
417-426: Well-implemented thread-safe lazy initialization.This implementation uses the double-checked locking pattern correctly:
- First check without synchronization to avoid lock overhead
- Synchronization on
thisto ensure thread safety- Second check inside synchronized block to prevent duplicate initialization
- Return of the initialized instance
The pattern ensures thread safety while minimizing synchronization overhead.
app/src/org/commcare/utils/Permissions.java (1)
122-123:Details
❓ Verification inconclusive
Reduced permission scope is good practice.
Removing
READ_MEDIA_IMAGESandREAD_MEDIA_VIDEOpermissions for Android Tiramisu (API 33+) and only requestingREAD_MEDIA_AUDIOaligns with the principle of least privilege. This change reduces the app's permission footprint, which is generally good for user privacy.Make sure to verify that the app still functions correctly without these permissions and that the corresponding permissions have also been removed from the AndroidManifest.xml file.
🏁 Script executed:
#!/bin/bash # Verify that the removed permissions don't appear in the AndroidManifest.xml file echo "Checking AndroidManifest.xml for removed permissions..." grep -n "READ_MEDIA_IMAGES\|READ_MEDIA_VIDEO" app/AndroidManifest.xmlLength of output: 192
Reduced permission scope verified – please confirm manifest cleanup manually
- The code change in
app/src/org/commcare/utils/Permissions.javanow returns onlyManifest.permission.READ_MEDIA_AUDIO, which is in line with the principle of least privilege.- The initial grep check on
app/AndroidManifest.xmlproduced no output forREAD_MEDIA_IMAGESorREAD_MEDIA_VIDEO. However, since the output was empty (and low-confidence), please manually verify (or run a broader search) to ensure these removed permissions are not referenced anywhere in the manifest files.- Also, confirm that the app still functions correctly without these additional permissions.
app/src/org/commcare/models/database/user/UserDatabaseUpgrader.java (2)
234-238: Database upgrade step follows established pattern.The conditional block to handle upgrading from database version 28 to 29 follows the same pattern as previous upgrades in this file. It correctly calls the new helper method and updates the version counter when successful.
800-811: Well-implemented database upgrade with proper transaction handling.The implementation correctly:
- Uses a transaction to ensure atomicity of database operations
- Drops the existing table before recreating it
- Marks the transaction as successful only when operations complete without errors
- Ensures the transaction is always ended, even if an exception occurs
This approach follows best practices for database migrations.
app/src/org/commcare/views/widgets/WidgetUtils.java (3)
3-3: Imports added for new functionality.The imports for
SuppressLint,PackageManager, andMediaStoreare necessary for the new media picker utility methods.Also applies to: 6-7
82-91: Well-implemented adaptive media selection utility.The
createPickMediaIntentmethod properly:
- Uses
@SuppressLint("InlinedApi")to suppress warnings about using newer APIs- Checks if the photo picker is supported before using the newer API
- Falls back to a more widely supported approach when needed
- Returns a properly configured intent with the specified MIME type
This implementation provides good backward compatibility while leveraging newer APIs when available.
93-98: Good implementation of feature detection.The
isPhotoPickerSupportedmethod properly:
- Creates an intent with the modern photo picker action
- Uses the system's PackageManager to check if any app can handle this intent
- Returns a boolean indicating availability
This approach correctly detects if the device supports the photo picker functionality, allowing for graceful fallback to older APIs when needed.
app/res/values/dimens.xml (2)
111-111: LGTM: Adding consistent vertical padding for progress barsAdding a standardized dimension for progress bar vertical padding (16dp) improves UI consistency and follows material design principles for proper component spacing.
60-63:Details
❓ Verification inconclusive
Font size increases improve accessibility
The substantial increases in font sizes (small: 8sp → 10sp, medium: 10sp → 14sp, large: 12sp → 16sp, xlarge: 14sp → 21sp) will significantly improve text readability throughout the application, especially for users with visual impairments.
However, these changes might affect layout flow in some screens where text previously fit within certain constraints. It would be good to verify that these changes don't cause unwanted text truncation or wrapping in key UI components.
🏁 Script executed:
#!/bin/bash # Search for TextViews that might be affected by the font size changes rg -A 1 "android:textSize=\"@dimen/font_size_(small|medium|large|xlarge)\"" --glob "*.xml" app/res/layout/Length of output: 5259
Font size increases verified – please manually check layouts for potential UI regressions
The increases (small: 8sp → 10sp, medium: 10sp → 14sp, large: 12sp → 16sp, xlarge: 14sp → 21sp) clearly boost readability and accessibility. Our search across layout files (e.g., screen_login.xml, update_activity.xml, square_card.xml, etc.) confirms that these updated dimens are consistently used. However, since increased text sizes could potentially disrupt layout flows (e.g., causing truncation or wrapping issues), please manually verify in key screens that the adjustments do not negatively impact the UI.
app/src/org/commcare/tasks/ConnectionDiagnosticTask.java (3)
3-11: Good refactoring: Centralizing network connectivity logicMoving the network connectivity check logic to the ConnectivityStatus class reduces code duplication and centralizes this functionality, making it easier to maintain in the future.
69-72: Improved error handling with consistent loggingRefactoring to use ConnectivityStatus.isNetworkAvailable instead of the local isOnline method and adding standardized logging messages for connection failures creates a more maintainable and consistent approach to handling network connectivity.
76-78: Added missing success loggingAdding the success log message in the final else block completes the logging structure, ensuring that all possible outcomes are properly logged.
app/src/org/commcare/fragments/EntitySubnodeDetailFragment.java (2)
82-83: Code formatting improvementThe method signature of deliverLoadResult has been reformatted for better readability, with parameters aligned properly.
56-56:Details
✅ Verification successful
Verify impact of passing null to EntityLoaderTask constructor
The EntityLoaderTask constructor now receives null as the second parameter (EntityDatum). According to the PR summary, this makes the task more flexible, but ensure this doesn't cause issues in specific use cases.
🏁 Script executed:
#!/bin/bash # Check the EntityLoaderTask constructor to understand the parameter usage rg -A 10 "EntityLoaderTask\(" --glob "*.java" app/src/Length of output: 3701
Subject: Confirmed – Passing null to EntityLoaderTask's constructor is safe
The constructor now explicitly marks the second parameter (EntityDatum) as nullable, and its usage in EntitySubnodeDetailFragment (passing null) aligns with this design. The underlying helper (EntityLoaderHelper) is expected to handle a null value appropriately, while other parts of the code (e.g., EntitySelectActivity) continue to pass a valid EntityDatum where needed. No adverse impact has been detected, so this change appears safe.
app/src/org/commcare/utils/ConnectivityStatus.java (2)
16-17: LGTM: Added standardized logging messagesAdding standardized logging messages for connectivity status improves debugging capabilities and ensures consistent error reporting across the application.
23-30:Details
❓ Verification inconclusive
Improved error handling with null check
Adding a null check for the ConnectivityManager is good defensive programming. The method now handles the case where the system service might not be available and logs this scenario appropriately.
However, I noticed that the check for network connectivity has been changed from
isConnectedOrConnecting()to justisConnected(). This might make the check slightly more strict.
🏁 Script executed:
#!/bin/bash # Search for other places in the codebase that might depend on isConnectedOrConnecting behavior rg "isConnectedOrConnecting" --glob "*.java" app/src/Length of output: 53
Action Required: Verify Connectivity Check Strictness
Great improvement on error handling with the added null check for the ConnectivityManager. Using a null check and logging when the system service isn’t available strengthens error handling. However, the change from using
isConnectedOrConnecting()toisConnected()introduces a stricter requirement for network connectivity. Although our automated search didn’t locate this method elsewhere in the codebase, please manually verify that this change does not affect any parts of the app that might expect the previous, more lenient behavior.
- Confirm that no components rely on the broader connectivity condition provided by
isConnectedOrConnecting().- Ensure that using
isConnected()meets all network availability requirements within the app.app/unit-tests/resources/commcare-apps/index_and_cache_test/suite.xml (3)
76-76: Added cache capability for entity details.The
cache_enabled="true"attribute added to the detail element enables caching functionality for the "m1_case_short" entity list, which aligns with the cache testing framework in the EntityListCacheIndexTest.
82-82: Field-level caching enabled.Enabling caching at the field level provides more granular control over which data elements are cached.
93-93:Details
❓ Verification inconclusive
Simplified sort attribute.
The removal of the
order="-2"attribute simplifies the sort element while maintaining the ascending direction. This change could affect the sorting priority if multiple sort fields exist.
🏁 Script executed:
#!/bin/bash # Check if there are other sort fields in the same detail that might need specific ordering rg "<sort" app/unit-tests/resources/commcare-apps/index_and_cache_test/suite.xml -A 5 -B 5Length of output: 896
Action: Verify Sorting Priority Adjustments
- The change removes the explicit
order="-2"attribute, simplifying the sort element to<sort type="string" direction="ascending">.- Our search shows that elsewhere in the file one sort element still uses an explicit order (e.g.,
order="1"), indicating that the relative ordering among multiple sort fields might be significant.- Please verify that this simplification does not inadvertently alter the intended sorting behavior when multiple sort fields are present.
app/src/org/commcare/android/database/connect/models/ConnectLearnModuleSummaryRecord.java (3)
1-13: New data model for Connect learn modules.Well-structured class with appropriate imports, package definition, and table annotation.
27-52: Properly annotated persistence fields.The fields are well-organized with appropriate persistence annotations and meta field mappings. Each field has a clear purpose and correct type for the data it represents.
70-88: Well-designed getter methods.The getter methods provide clean access to the object's properties, following good encapsulation practices.
app/src/org/commcare/android/database/connect/models/ConnectJobRecordV7.java (2)
46-112: Comprehensive data model with proper annotations.The fields are well-organized with appropriate persistence annotations and meta field mappings, ensuring proper database storage and retrieval.
218-246: V4 to V7 migration correctly sets default values.The migration from V4 to V7 correctly maps all fields and sets appropriate defaults for new fields, including dates and the isActive flag.
app/unit-tests/src/org/commcare/android/tests/caselist/EntityListCacheIndexTest.java (3)
41-50: Well-implemented parameterized testing.Converting to parameterized tests allows testing the caching functionality with both bulk processing enabled and disabled, which provides better test coverage.
60-67: Effective use of Mockito for developer preferences.Using Mockito's static mocking capability to control the
isBulkPerformanceEnabledpreference allows testing different processing modes without changing actual preferences.
72-85: Comprehensive cache validation test.The test verifies both that the cache is properly populated and that it's correctly invalidated when case data changes. This ensures the cache behaves as expected in real-world scenarios.
app/src/org/commcare/entity/AndroidAsyncNodeEntityFactory.kt (4)
1-8: Imports and package definition look fine.
No issues identified regarding syntax or correctness.
25-31: Constructor initialization is consistent with the superclass.
All constructor parameters, including nullableEvaluationContext, appear to be passed to the parent class correctly.
44-77: Watch for potential concurrency issues inprepareEntitiesInternal.
While the logic to cancel or observe ongoing work appears correct, be wary of race conditions if multiple calls to this method run concurrently. Consider adding synchronization or ensuring single-thread usage to avoid concurrent cancellations or re-primes.
125-127: Utility method usage.
getCurrentCommandId()is straightforward and correct for retrieving the current command ID from the application session.app/src/org/commcare/android/database/connect/models/ConnectJobRecord.java (2)
157-163: Default constructor sets multiple date fields tonew Date().
Confirm whether initializingdateClaimed,lastDeliveryUpdate, etc., to the current date is desired for every new record. If not, consider separate initialization logic or a specialized constructor.
561-597:fromV7method might skip newly introduced fields.
The code setsisUserSuspendedto false by default. Verify that this is correct if the old record type had no equivalent field. If partial migration is acceptable, this is fine. Otherwise, consider capturing more states from older versions if available.app/src/org/commcare/CommCareApplication.java (4)
210-213: Ensure consistent usage ofinvalidateCacheOnRestore.
Revisit where this flag is set and consumed to confirm that caches are properly invalidated when needed.
314-320:backgroundSyncSafeflag usage seems clear.
Providing lightweight getters and setters is straightforward. No further issues observed.
1170-1176: Encryption key provider integration.
Setting and gettingencryptionKeyProvideris straightforward. Ensure that any key rotation or re-initialization needs are handled at higher layers if required.
1260-1271: NewscheduleEntityCacheInvalidationmethod.
Good approach to invalidate unused cached entities. Confirm that theCommCareEntityStorageCacheis properly referenced when there are multiple app contexts or multiple user sessions.app/src/org/commcare/connect/network/SsoToken.java (1)
51-54: 🛠️ Refactor suggestionAdd proper field initialization in default constructor
The empty constructor doesn't initialize any fields, which could lead to unexpected behavior if the object is persisted before fields are set.
public ConnectJobLearningRecord() { - + this.lastUpdate = new Date(); }Likely an incorrect or invalid review comment.
.github/pull_request_template.md (1)
1-42: PR template improvements look great!The restructuring of the PR template provides better organization and clarity. The addition of the Technical Summary, Safety Assurance, and QA Plan sections will help ensure more comprehensive pull request descriptions.
app/src/org/commcare/tasks/EntityLoaderTask.java (8)
7-7: New import for EntityLoadingProgressListener interface.This import supports the new progress reporting functionality being added to the task.
10-10: New import for EntityDatum model.This import supports the additional parameter in the constructor.
19-19: Added Nullable annotation import.Good practice to use @nullable annotation for optional parameters.
25-27: Class now implements EntityLoadingProgressListener.The EntityLoaderTask now implements EntityLoadingProgressListener to provide progress updates during entity loading.
35-35: New field for controlling progress updates.This boolean field is used to determine whether to deliver progress updates based on the detail's optimization setting.
37-48: Updated constructor with additional parameters.The constructor now accepts an EntityDatum parameter and initializes the provideDetailProgressUpdates field based on the detail's optimization setting. Good use of the @nullable annotation for the optional entityDatum parameter.
53-53: Now passing 'this' as progress listener.The loadEntities method now receives the current task instance as a progress listener, enabling progress reporting during entity loading.
132-142: Implementation of progress reporting methods.The class now implements the EntityLoadingProgressListener interface by providing these two methods:
- publishEntityLoadingProgress - Publishes the progress updates
- onProgressUpdate - Delivers progress to the listener if conditions are met
These additions allow for real-time progress tracking during entity loading.
app/src/org/commcare/activities/EntitySelectActivity.java (13)
37-37: New import for EntityLoadingProgressListener.This import supports the progress reporting functionality implementation.
56-56: New import for PrimeEntityCacheHelper.This import enables the observation of entity cache priming progress.
62-62: Import for StringUtils.This import supports the new string formatting used in progress messages.
171-173: New fields for progress tracking.These fields enhance the UI experience by tracking:
- visibleView: Reference to the current list/grid view
- progressTv: Reference to the text view showing progress information
- lastProgress: Tracks the last progress value to avoid redundant updates
275-275: Initialize the progress text view.Assigns the progress text view reference which will display loading status messages.
364-364: Updated visibility reference.Changed from entity_select_loading to progress_container for consistency with other UI changes.
484-489: Enhanced entity loading with progress status.The loadEntities method now:
- Sets an initial progress message
- Creates the EntityLoaderTask with the selectDatum parameter
- Calls observePrimeCacheWorker to monitor cache priming progress
These changes improve the user experience by providing visual feedback during loading.
494-505: New method to monitor entity cache priming.This method observes the progress of the prime entity cache worker and delivers progress updates to the UI when relevant. It checks if both the data ID and detail ID match the current context before updating the UI.
875-875: Updated progress message during result delivery.Sets a "finishing" message when entity loading completes, improving user experience.
897-897: Updated progress container visibility.Consistent with earlier changes, hides the progress container after loading completes.
921-923: New helper method for setting progress text.Encapsulates the progress text update logic in a dedicated method for better code organization.
951-951: Updated progress container visibility.Consistent reference to progress_container when attaching a loader.
1012-1031: Implementation of the deliverProgress method.This method provides detailed progress feedback during entity loading by:
- Converting the progress value to a percentage
- Setting appropriate messages based on the loading phase
- Only updating when the progress percentage changes
- Using localized strings for different loading phases
This significantly improves the user experience during entity loading operations.
app/src/org/commcare/android/database/connect/models/ConnectJobAssessmentRecord.java (4)
1-22: New ConnectJobAssessmentRecord class with proper database annotations.This class provides a data model for Connect job assessments with appropriate imports, documentation, and database table annotation.
23-33: Well-defined storage key and metadata constants.Good practice to define constants for storage key and metadata field names, improving code readability and maintainability.
34-50: Model fields with proper persistence annotations.Fields are properly annotated with @persisting and @metafield for database storage, with appropriate ordering indices and metadata keys.
56-68: Factory method for creating record from JSON.The fromJson method properly initializes all fields from the JSON object and handles potential exceptions. The lastUpdate field is correctly initialized with the current date.
app/src/org/commcare/connect/database/ConnectUserDatabaseUtil.java (5)
1-13: New utility class for Connect user database operations.This class provides centralized management of Connect user records with appropriate imports and a synchronization lock.
14-35: Well-implemented getUser method with proper error handling.The getUser method includes:
- Null context validation
- Synchronized access to prevent concurrency issues
- Database existence check
- Proper exception handling with logging
- Clear return value handling
This implementation ensures safe and consistent user record retrieval.
37-52: Robust storeUser method with parameter validation.The storeUser method includes:
- Thorough parameter validation for both context and user
- Synchronized access
- Proper exception handling with descriptive error messages
- Appropriate logging
This implementation ensures data integrity when storing user records.
54-74: Comprehensive forgetUser method with proper cleanup.The forgetUser method:
- Validates the context parameter
- Uses synchronized access
- Performs complete cleanup (database deletion and key removal)
- Handles specific exception types with appropriate error messages
- Resets the database broken flag
This implementation ensures thorough cleanup of user data.
14-35:Details
❓ Verification inconclusive
Consider handling multiple user records case.
The getUser method returns the first user record if multiple exist. This may lead to unexpected behavior if more than one user record is present.
🏁 Script executed:
#!/bin/bash # Verify if multiple user records are handled in other parts of the codebase # Check for any code that iterates through all user records rg -A 2 -B 2 "ConnectUserRecord.*iterator\(\)\.hasNext\(\)" --glob "*.java" # Check if there's any code that filters users or expects multiple users rg -A 2 -B 2 "for.*ConnectUserRecord" --glob "*.java"Length of output: 133
Action Required: Verify Handling for Multiple User Records
The current implementation of
getUserinConnectUserDatabaseUtil.javareturns the firstConnectUserRecordwithout any explicit check or error handling when multiple records exist. Our initial search did not reveal any additional logic elsewhere in the codebase that handles or filters multiple user records, leaving the intended behavior in cases with more than one record unclear. Please manually verify whether the application is designed to enforce a unique user record (e.g., via database constraints or additional business logic) or if this method should be updated to handle multiple records more explicitly (e.g., by throwing an error or selecting based on additional criteria).
- File: app/src/org/commcare/connect/database/ConnectUserDatabaseUtil.java, Lines: 14-35
- Suggestion: Confirm if a uniqueness constraint exists elsewhere (for example, within
ConnectDatabaseHelper.getConnectStorageorConnectUserRecorddefinitions) that prevents multiple records. If not, consider implementing explicit handling for scenarios where more than one user record is present or document the behavior clearly.app/src/org/commcare/connect/database/ConnectDatabaseHelper.java (3)
32-43: Consider synchronizing access toconnectDatabasewhen rekeying.
Currently,handleReceivedDbPassphrasedoes not synchronize onconnectDbHandleLockwhileconnectDatabaseis used and possibly rekeyed. In multi-threaded scenarios, this could lead to race conditions when other methods (likegetConnectStorage) attempt to open or read from the database concurrently.Would you like to investigate potential concurrency issues with a script searching for all references to
handleReceivedDbPassphraseand verifying they are wrapped in a synchronized block?
86-100: Teardown and corrupt DB handling look consistent.
These sections appear correct and intentionally synchronized. The code for invalid DB teardown and corruption mapping is logical.
102-114: Updates to linked records and user registration phase are straightforward.
The read-modify-write steps are clear, though additional error handling or concurrency checks might be warranted if multiple threads can modify the same records concurrently.app/src/org/commcare/connect/database/ConnectDatabaseUtils.java (2)
16-34: Passphrase storage and encryption flow looks well-structured.
Storing the passphrase in encrypted form is a good security practice. Throwing an exception for null or empty passphrases also helps maintain data integrity.
45-53: Overloaded method usage is appropriate.
Decoding from Base64 before delegating to the byte-array-based API centralizes encryption logic. Good job maintaining consistent error-handling.app/src/org/commcare/utils/EncryptionKeyProvider.java (1)
37-155: Static analysis falsely flags TDES and ECB usage.
No TDES is actually in use, and AES is combined with CBC/Padding in modern devices. The reference to “ECB” is part of the standard RSA transformation naming convention, not AES. This appears to be a false positive from the tool.🧰 Tools
🪛 ast-grep (0.31.1)
[warning] 60-60: Triple DES (3DES or DESede) is considered deprecated. AES is the recommended cipher. Upgrade to use AES.
Context: KeyStore.getInstance(KEYSTORE_NAME)
Note: [CWE-326]: Inadequate Encryption Strength [OWASP A03:2017]: Sensitive Data Exposure [OWASP A02:2021]: Cryptographic Failures [REFERENCES]
- https://find-sec-bugs.github.io/bugs.htm#TDES_USAGE
- https://csrc.nist.gov/News/2017/Update-to-Current-Use-and-Deprecation-of-TDEA(desede-is-deprecated-java)
[warning] 116-117: Triple DES (3DES or DESede) is considered deprecated. AES is the recommended cipher. Upgrade to use AES.
Context: KeyGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_AES, KEYSTORE_NAME)
Note: [CWE-326]: Inadequate Encryption Strength [OWASP A03:2017]: Sensitive Data Exposure [OWASP A02:2021]: Cryptographic Failures [REFERENCES]
- https://find-sec-bugs.github.io/bugs.htm#TDES_USAGE
- https://csrc.nist.gov/News/2017/Update-to-Current-Use-and-Deprecation-of-TDEA(desede-is-deprecated-java)
[warning] 127-127: Triple DES (3DES or DESede) is considered deprecated. AES is the recommended cipher. Upgrade to use AES.
Context: KeyPairGenerator.getInstance("RSA", KEYSTORE_NAME)
Note: [CWE-326]: Inadequate Encryption Strength [OWASP A03:2017]: Sensitive Data Exposure [OWASP A02:2021]: Cryptographic Failures [REFERENCES]
- https://find-sec-bugs.github.io/bugs.htm#TDES_USAGE
- https://csrc.nist.gov/News/2017/Update-to-Current-Use-and-Deprecation-of-TDEA(desede-is-deprecated-java)
[warning] 60-60: Use of AES with ECB mode detected. ECB doesn't provide message confidentiality and is not semantically secure so should not be used. Instead, use a strong, secure cipher: Cipher.getInstance("AES/CBC/PKCS7PADDING"). See https://owasp.org/www-community/Using_the_Java_Cryptographic_Extensions for more information.
Context: KeyStore.getInstance(KEYSTORE_NAME)
Note: [CWE-327]: Use of a Broken or Risky Cryptographic Algorithm [OWASP A03:2017]: Sensitive Data Exposure [OWASP A02:2021]: Cryptographic Failures [REFERENCES]
- https://owasp.org/Top10/A02_2021-Cryptographic_Failures
- https://googleprojectzero.blogspot.com/2022/10/rc4-is-still-considered-harmful.html(use-of-aes-ecb-java)
[warning] 116-117: Use of AES with ECB mode detected. ECB doesn't provide message confidentiality and is not semantically secure so should not be used. Instead, use a strong, secure cipher: Cipher.getInstance("AES/CBC/PKCS7PADDING"). See https://owasp.org/www-community/Using_the_Java_Cryptographic_Extensions for more information.
Context: KeyGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_AES, KEYSTORE_NAME)
Note: [CWE-327]: Use of a Broken or Risky Cryptographic Algorithm [OWASP A03:2017]: Sensitive Data Exposure [OWASP A02:2021]: Cryptographic Failures [REFERENCES]
- https://owasp.org/Top10/A02_2021-Cryptographic_Failures
- https://googleprojectzero.blogspot.com/2022/10/rc4-is-still-considered-harmful.html(use-of-aes-ecb-java)
[warning] 127-127: Use of AES with ECB mode detected. ECB doesn't provide message confidentiality and is not semantically secure so should not be used. Instead, use a strong, secure cipher: Cipher.getInstance("AES/CBC/PKCS7PADDING"). See https://owasp.org/www-community/Using_the_Java_Cryptographic_Extensions for more information.
Context: KeyPairGenerator.getInstance("RSA", KEYSTORE_NAME)
Note: [CWE-327]: Use of a Broken or Risky Cryptographic Algorithm [OWASP A03:2017]: Sensitive Data Exposure [OWASP A02:2021]: Cryptographic Failures [REFERENCES]
- https://owasp.org/Top10/A02_2021-Cryptographic_Failures
- https://googleprojectzero.blogspot.com/2022/10/rc4-is-still-considered-harmful.html(use-of-aes-ecb-java)
app/src/org/commcare/android/database/connect/models/ConnectAppRecord.java (2)
63-64: Returning a mutable list reference can allow external modification.
As learned from theConnectLinkedAppRecordprecedent, these getters/setters remain straightforward. However, consider whether returning unmodifiable views or making defensive copies might be beneficial in future to avoid accidental mutations.
69-91:Details
✅ Verification successful
Verify that missing or optional JSON fields are handled gracefully.
ThefromJsonmethod can throwJSONExceptionwhen the JSON input lacks necessary keys. Confirm whether callers will always supply all fields or if additional error handling is advisable.Generate a script to locate all current usages of
fromJsonand see if any usage might omit these mandatory fields:
🏁 Script executed:
#!/bin/bash rg -A 5 'ConnectAppRecord\.fromJson\('Length of output: 953
Confirmation of JSON Field Handling
After reviewing the call sites (in
app/src/org/commcare/android/database/connect/models/ConnectJobRecord.java), we found that both usages ofConnectAppRecord.fromJsonpass a JSONObject obtained viagetJSONObject(i.e. for both the learn and delivery apps). This indicates that the callers expect and ensure that all required JSON fields are present. The current design follows a fail-fast approach by letting a missing field raise aJSONExceptionimmediately. If later requirements arise for handling optional JSON fields gracefully, consider switching to methods likeoptString,optInt, etc.app/unit-tests/src/org/commcare/android/tests/processing/FormStorageTest.java (1)
362-383: Good job maintaining backward compatibility with newly added classes.
These recently added connect-related record classes are now registered in the externalizable test list, ensuring that older user data remains deserializable upon upgrade. Please confirm that each class indeed implements or inherits the necessary serialization logic.app/src/org/commcare/tasks/EntityLoaderHelper.kt (5)
19-21: Class documentation is clear and properly placed.
The added KDoc for the class provides a concise overview of its role. This is helpful for future maintainers.
53-58: Progress-driven loading is a welcome enhancement.
The additionalprogressListenerparameter inloadEntitiesnicely supports UI/UX feedback. Implementation appears consistent with the existing expansion logic.
85-87: Ensure the loading loop handles large data sets.
Iterating over references with frequent listener notifications is helpful for progress reporting. Confirm it remains performant under large sets, or consider batching updates to reduce overhead if needed.Also applies to: 92-96
114-114: Practical approach to cancellation.
Callingfactory.cancelLoading()complements thestopLoadingflag. This layered cancellation strategy ensures a responsive user experience when halting loading processes.
24-26:Details
✅ Verification successful
Request a usage audit for constructor parameters.
Introducing the newsessionDatumandinBackgroundparameters shifts the initialization approach. Validate any existing invocations or subclasses to ensure they supply correct arguments.
🏁 Script executed:
#!/bin/bash # Search for all direct usages of EntityLoaderHelper to verify updated constructor calls rg -A 3 'EntityLoaderHelper\('Length of output: 1237
Usage Audit Complete: Constructor Parameters Correctly Supplied
- Verified that both
app/src/org/commcare/tasks/PrimeEntityCacheHelper.ktandapp/src/org/commcare/tasks/EntityLoaderTask.javacorrectly pass the newsessionDatumandinBackgroundparameters along with the existing ones.- All identified usages appear updated and consistent with the new constructor signature. No additional action is required for subclasses or other invocations at this time.
app/res/values/strings.xml (2)
14-16: Ensure consistent usage of server endpoints
No major issues found. The naming is consistent with other connectivity strings in the file.
468-476: New progress states look good
These progress states provide clearer feedback to users while cases are being processed.app/src/org/commcare/models/database/connect/ConnectDatabaseUpgrader.java (1)
440-452: Table creation logic is clear
This helper method keeps table creation consistent and tidy within a transaction. Good approach.app/src/org/commcare/models/database/connect/DatabaseConnectOpenHelper.java (1)
142-147: Partial upgrade concerns repeated
This upgrade flow relies onConnectDatabaseUpgrader, which does not rethrow exceptions on migration errors, potentially allowing partial upgrades.app/src/org/commcare/utils/EncryptionUtils.java (2)
84-111: Validate and guard against large payload sizes in the 2-byte length fields.
Your encrypted output arranges two bytes for the encrypted payload length, capping at 65535 bytes. If payloads might exceed this size in the future, consider a larger field or throw a more explicit error.
167-176: Reevaluate usage of MD5 hash for potential security implications.
MD5 is collision-prone if used for cryptographic purposes. If this is purely for checksums, no action is needed, but consider using safer alternatives (e.g., SHA-256) if security is a concern.🧰 Tools
🪛 ast-grep (0.31.1)
[warning] 168-168: Detected MD5 hash algorithm which is considered insecure. MD5 is not collision resistant and is therefore not suitable as a cryptographic signature. Use HMAC instead.
Context: "MD5"
Note: [CWE-328] Use of Weak Hash. [REFERENCES]
- https://owasp.org/Top10/A02_2021-Cryptographic_Failures(use-of-md5-java)
app/src/org/commcare/connect/network/ConnectNetworkHelper.java (2)
80-86: Potential concurrency consideration in isBusy() usage.
isBusyandcallInProgressrely on the same volatile field but the approach lacks synchronization around setting and checking. This is likely safe for your scenario, but be mindful that rapid consecutive calls could miss race conditions.
193-213: Check for JSON or form encoding mismatch in buildPostFormHeaders.
When usinguseFormEncoding=false, you switch to JSON, but there's no immediate check for content type consistency if the server expects a different format. Consider verifying or logging the content type to avoid silent mismatches.app/src/org/commcare/models/database/user/models/CommCareEntityStorageCache.java (3)
81-81: Confirm the default value and usage pattern for COL_IS_SHALLOW.
You set a default of 0 foris_shallow. This is sensible, but ensure that the creation of new rows for unaffected records also matches this expectation—particularly if other code paths insert partial records.
136-145: Confirm correct data type usage for record IDs.
invalidateRecordparses theStringrecordId viaInteger.parseInt(recordId). If you expect large numeric IDs or non-integer keys, verify that this parse step won’t fail or silently truncate.
146-160: Consider verifying partial invalidations for consistency.
When callinginvalidateRecords(), records are marked shallow within a transaction. Make sure the logic ensures atomicity across all record IDs and doesn't leave partial data if the transaction is rolled back.app/src/org/commcare/connect/database/JobStoreManager.java (2)
27-44: Consider potential concurrent access or partial updates.
While the transaction handling here is robust, concurrent calls to this method might still cause race conditions if multiple threads invokestoreJobssimultaneously. You may want to confirm that only a single thread can callstoreJobsat a time or introduce locks to ensure atomic updates under parallel usage.Would you like a script to scan for concurrent invocations of
storeJobs, or do you already enforce single-threaded access higher up?
129-218: No immediate issues found for these remaining methods.
The logic for storing related entities (storeAppInfo,storeModules,storePaymentUnits) and retrieving composite jobs appears coherent and consistent.app/src/org/commcare/android/database/connect/models/ConnectJobPaymentRecord.java (2)
79-95: Verify JSON field resilience.
Retrieving an integer fromjson.getInt(META_AMOUNT)could fail if the value does not exist or is out of the integer range. Please ensure upstream code validates or gracefully handles these cases, especially for unexpectedly large or malformed input.Would you like me to generate a script to search for all calls to
fromJsonand check how JSON data is validated before calling this method?
1-78: Overall structure is clear.
Your approach in storingamountas aStringaligns with the historical design choice mentioned in the learnings. The rest of the model is well-organized.Also applies to: 96-126, 154-155
app/src/org/commcare/android/database/connect/models/ConnectJobDeliveryRecordV2.java (3)
17-18: Class definition is clear and aligns with CommCare data models.
This class appropriately extendsPersistedand implementsSerializable, matching the typical pattern for CommCare’s database models.
61-65: Default constructor is appropriate for serialization.
Having an empty constructor reinforces the serialization requirements for database objects.
67-101: Getters provide straightforward read access.
These methods are aligned with best practices; no concurrency or null checks needed as the data flow guarantees non-null fields.app/src/org/commcare/tasks/PrimeEntityCacheHelper.kt (4)
56-79: Worker scheduling approach is coherent.
UsingWorkManagerwithenqueueUniqueWorkhelps avoid overlapping job scheduling for prime entity cache. This is a good pattern for background tasks.
81-84: Cancellation logic is consistent with thecancelWorkmethod.
Calling bothcancel()on this helper andcancelUniqueWork()fromWorkManagerensures ongoing background operations are invalidated properly.
155-179: Robust handling of pre-fetched vs. on-demand entities.
The code properly differentiates between pre-passedentitiesand those loaded vianodeset. This design is flexible and keeps the caching logic centralized inEntityLoaderHelper.
30-44:Details
✅ Verification successful
Volatile flags and synchronized methods appear consistent, but verify concurrency requirements.
You are using both@Synchronizedfor methods and@Volatilefor flags likeinProgressandcancelled. This generally works, but ensure no other threads mutate these variables outside the synchronized methods, potentially leading to partial visibility.Do you want to run a quick check for any unsynchronized usage of
inProgressorcancelledacross the codebase?
🏁 Script executed:
#!/bin/bash # Searching for 'inProgress' and 'cancelled' usage outside of synchronized methods rg --context 5 "inProgress|cancelled"Length of output: 62853
Concurrency flags in PrimeEntityCacheHelper.kt verified – no unsynchronized mutations found
The volatile fields (
inProgressandcancelled) confined to this class are only used for simple visibility checks and are not being altered outside of their intended methods. The shell script search confirmed that there is no unsynchronized usage in other parts of the codebase, so the current approach meets the concurrency requirements. Please continue to ensure any future access maintains this consistency.app/src/org/commcare/android/database/connect/models/ConnectJobRecordV4.java (3)
20-21: Table annotation is correct for storing Connect job records.
Defining@Table(ConnectJobRecordV4.STORAGE_KEY)properly ties the model to the designated storage key.
47-106: Data fields and metadata follow a consistent pattern.
These fields, annotated with@Persistingand@MetaField, align well with the intended usage in CommCare’s data persistence layer.
156-166: Graceful fallback forpaymentAccruedparsing.
Returning 0 and logging an error is a safe way to handle malformed or unset paymentAccrued data. This approach avoids runtime failures and preserves application stability.app/src/org/commcare/android/database/connect/models/ConnectJobDeliveryRecord.java (1)
147-162: Confirm reasoning for resettingreasonto an empty string.The
fromV2migration method setsreasonto""instead of copying from the older record. Validate whether you require the old reason value or if clearing is intentional.app/src/org/commcare/connect/database/ConnectJobUtils.java (2)
25-29: Validate 'upsertJob' results or errors.
Currently,upsertJob()doesn't handle any failures fromstoreJobs(...). Consider checking return status or surrounding it with a try-catch to detect potential write errors and handle them gracefully.Would you like a shell script that checks for the usage of
storeJobsreturn values or exceptions across the codebase to confirm error handling?
31-39:Details
❓ Verification inconclusive
Confirm only one job per job ID is expected.
getCompositeJob()always returns the first record if multiple records share the same jobId. Verify that jobId collisions are impossible or intentional.
🏁 Script executed:
#!/bin/bash # Searching for ConnectJobRecord inserts to confirm we never insert multiple records with the same jobId ast-grep --pattern $'new ConnectJobRecord($_, $_, $_)'Length of output: 55
Action: Manual Verification Needed for Job ID Uniqueness
The ast-grep search for instantiations using the three-argument constructor did not return any output, so we cannot confirm from this query alone whether duplicate job IDs might be inserted. Please verify manually that all insertion paths for
ConnectJobRecordenforce unique job IDs—either by design or via database constraints. Specifically, review:
- All usages of the
ConnectJobRecordconstructor and insertion mechanisms.- The logic in
ConnectDatabaseHelperthat handles record creation for potential duplicatejobIdvalues.app/src/org/commcare/android/database/connect/models/ConnectLinkedAppRecord.java (3)
40-40: Confirm intentional plain-text password storage.
Storing passwords in plain text can be risky. The retrieved learnings indicate this is intentional, but re-verify business requirements to ensure no encryption or hashing is necessary.
71-76: Scrutinize default Date assignments.
All date fields default to the current date in the no-arg constructor. Confirm that automatically populating fields likelinkOfferDate1,linkOfferDate2, andlastAccessedwithnew Date()on record creation aligns with business needs.
128-131: Double-check password update logic.
linkToConnectId(...)overwrites the password unconditionally. Confirm this flow aligns with your security requirements and audit logging (if needed).
| public void setPassword(String password) { | ||
| this.password = password; | ||
| } |
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.
🛠️ Refactor suggestion
Consider adding password hashing in setPassword method.
The setPassword method directly sets the password field. Consider adding password hashing for better security.
public void setPassword(String password) {
- this.password = password;
+ this.password = hashPassword(password);
+ this.lastPasswordDate = new Date();
}
+
+/**
+ * Hashes the provided plain text password using a secure algorithm.
+ * @param plainTextPassword The password to hash
+ * @return The hashed password
+ */
+private String hashPassword(String plainTextPassword) {
+ // Implement a secure hashing algorithm
+ // Example: return BCrypt.hashpw(plainTextPassword, BCrypt.gensalt());
+ return plainTextPassword; // Replace with actual implementation
+}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| public void setPassword(String password) { | |
| this.password = password; | |
| } | |
| public void setPassword(String password) { | |
| - this.password = password; | |
| + this.password = hashPassword(password); | |
| + this.lastPasswordDate = new Date(); | |
| } | |
| + /** | |
| + * Hashes the provided plain text password using a secure algorithm. | |
| + * @param plainTextPassword The password to hash | |
| + * @return The hashed password | |
| + */ | |
| + private String hashPassword(String plainTextPassword) { | |
| + // Implement a secure hashing algorithm | |
| + // Example: return BCrypt.hashpw(plainTextPassword, BCrypt.gensalt()); | |
| + return plainTextPassword; // Replace with actual implementation | |
| + } |
| testImplementation 'org.mockito:mockito-core:5.5.0' | ||
| testImplementation 'org.json:json:20140107' |
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.
Resolve conflicting JSON library dependencies.
You've included two different versions of the same JSON library as test dependencies:
org.json:json:20231013(line 46)org.json:json:20140107(line 48)
This could lead to unpredictable behavior in tests depending on which version gets loaded first.
testImplementation 'org.json:json:20231013'
-testImplementation 'org.json:json:20140107'Choose the newer version and remove the older one, unless there's a specific requirement for the older version.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| testImplementation 'org.mockito:mockito-core:5.5.0' | |
| testImplementation 'org.json:json:20140107' | |
| testImplementation 'org.json:json:20231013' | |
| testImplementation 'org.mockito:mockito-core:5.5.0' |
| ///Todo retry part of the api fails | ||
|
|
||
| public class ApiClient { | ||
| public static final String BASE_URL = "https://connectid.dimagi.com"; // Replace with actual base URL |
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.
🛠️ Refactor suggestion
Avoid hardcoding the base URL.
The base URL is hardcoded to "https://connectid.dimagi.com", which makes it difficult to use different environments (staging, testing, etc.).
Consider:
- Reading the URL from a configuration file or BuildConfig
- Creating different flavors for different environments
- Adding a way to override the URL for testing
- public static final String BASE_URL = "https://connectid.dimagi.com"; // Replace with actual base URL
+ public static final String BASE_URL = BuildConfig.CONNECT_ID_BASE_URL; // Configurable per environment📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| public static final String BASE_URL = "https://connectid.dimagi.com"; // Replace with actual base URL | |
| public static final String BASE_URL = BuildConfig.CONNECT_ID_BASE_URL; // Configurable per environment |
| private String cachedUserPassword; | ||
|
|
||
| private final ArrayList<Throwable> asyncExceptions = new ArrayList<>(); | ||
| private boolean skipWorkManager = false; |
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.
🛠️ Refactor suggestion
Implement the use of skipWorkManager flag.
You've added a skipWorkManager flag and a method to set it, but the flag is never used in the code. The initWorkManager method doesn't check this flag before initializing the WorkManager.
public void initWorkManager() {
+ if (skipWorkManager) {
+ return;
+ }
Context context = ApplicationProvider.getApplicationContext();
try {
// first try to get instance to see if it's already initialised
WorkManager.getInstance(context);
} catch (IllegalStateException e) {
Configuration config = new Configuration.Builder()
.setMinimumLoggingLevel(Log.DEBUG)
.build();
WorkManager.initialize(context, config);
}
}Also, consider modifying the cancelWorkManagerTasks method to respect this flag.
Also applies to: 104-115, 324-326
|
|
||
| void deliverProgress(Integer... values); |
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.
💡 Verification agent
🧩 Analysis chain
LGTM! Good enhancement for progress reporting.
Adding this method to the interface enables progress reporting during entity loading operations, which will improve user experience by providing feedback during potentially lengthy operations.
Verify that all implementing classes have been updated to support this new method:
🏁 Script executed:
#!/bin/bash
# Find all classes that implement EntityLoaderListener
echo "Searching for classes implementing EntityLoaderListener..."
rg "implements.*EntityLoaderListener" -l
# Check if they implement the new deliverProgress method
echo "Checking implementations of deliverProgress method..."
rg "void\s+deliverProgress\s*\(\s*Integer\.\.\.\s*values\s*\)" --files-with-matchesLength of output: 547
Action required: Implement deliverProgress in all concrete implementations
While the enhancement to support progress reporting by adding the new method is a good improvement, our verification shows that the concrete classes implementing EntityLoaderListener (namely, app/src/org/commcare/activities/EntitySelectActivity.java and app/src/org/commcare/fragments/EntitySubnodeDetailFragment.java) have not been updated to override the new deliverProgress(Integer... values) method.
- EntitySelectActivity.java: Missing an override for
deliverProgress. - EntitySubnodeDetailFragment.java: Missing an override for
deliverProgress.
Please update these classes to include an appropriate implementation (or delegate) for deliverProgress to ensure consistent progress reporting during entity loading operations.
| public void upgrade(SQLiteDatabase db, int oldVersion, int newVersion) { | ||
| if (oldVersion == 1) { | ||
| upgradeOneTwo(db); | ||
| oldVersion = 2; | ||
| } | ||
|
|
||
| if (oldVersion == 2) { | ||
| upgradeTwoThree(db); | ||
| oldVersion = 3; | ||
| } | ||
|
|
||
| if (oldVersion == 3) { | ||
| upgradeThreeFour(db); | ||
| oldVersion = 4; | ||
| } | ||
|
|
||
| if (oldVersion == 4) { | ||
| upgradeFourFive(db); | ||
| oldVersion = 5; | ||
| } | ||
|
|
||
| if (oldVersion == 5) { | ||
| upgradeFiveSix(db); | ||
| oldVersion = 6; | ||
| } | ||
|
|
||
| if (oldVersion == 6) { | ||
| upgradeSixSeven(db); | ||
| oldVersion = 7; | ||
| } | ||
|
|
||
| if (oldVersion == 7) { | ||
| upgradeSevenEight(db); | ||
| oldVersion = 8; | ||
| } | ||
|
|
||
| if (oldVersion == 8) { | ||
| upgradeEightNine(db); | ||
| oldVersion = 9; | ||
| } | ||
|
|
||
| if (oldVersion == 9) { | ||
| upgradeNineTen(db); | ||
| oldVersion = 10; | ||
| } | ||
| } |
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.
Potential partial upgrade concerns
Because the upgrade method does not rethrow on error in sub-upgrade methods (e.g., upgradeTwoThree), oldVersion may still be incremented even if a failure occurs. This can result in data corruption or incomplete migrations for subsequent steps. Consider rethrowing the exception or otherwise aborting subsequent upgrades if a failure is encountered.
-} catch (Exception e){
- CrashUtil.log(e.getMessage());
-}
+} catch (Exception e){
+ CrashUtil.log(e.getMessage());
+ throw e; // Rethrow to prevent partial upgrade
+}Committable suggestion skipped: line range outside the PR's diff.
| public static byte[] decrypt(byte[] bytes, EncryptionKeyAndTransform keyAndTransform) | ||
| throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, | ||
| InvalidKeyException, IllegalBlockSizeException, BadPaddingException, | ||
| UnrecoverableEntryException { | ||
| int readIndex = 0; | ||
| int ivLength = bytes[readIndex] & 0xFF; | ||
| readIndex++; | ||
| if (ivLength < 0) { | ||
| //Note: Early chance to catch decryption error | ||
| throw new UnrecoverableKeyException("Negative IV length"); | ||
| } | ||
| byte[] iv = null; | ||
| if (ivLength > 0) { | ||
| iv = new byte[ivLength]; | ||
| System.arraycopy(bytes, readIndex, iv, 0, ivLength); | ||
| readIndex += ivLength; | ||
| } | ||
|
|
||
| int encryptedLength = (bytes[readIndex] & 0xFF) << 8; | ||
| readIndex++; | ||
| encryptedLength += (bytes[readIndex] & 0xFF); | ||
|
|
||
| byte[] encrypted = new byte[encryptedLength]; | ||
| readIndex++; | ||
| System.arraycopy(bytes, readIndex, encrypted, 0, encryptedLength); | ||
|
|
||
| Cipher cipher = Cipher.getInstance(keyAndTransform.getTransformation()); | ||
|
|
||
| cipher.init(Cipher.DECRYPT_MODE, keyAndTransform.getKey(), iv != null ? new IvParameterSpec(iv) : null); | ||
|
|
||
| return cipher.doFinal(encrypted); | ||
| } |
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.
🛠️ Refactor suggestion
Enhance input validation for stronger resilience against malformed data.
While you already check for negative IV length, a malicious byte array could contain large or nonsensical lengths. Consider validating the IV length and encrypted payload length more thoroughly (e.g., verifying they won’t exceed bytes.length - readIndex).
| public static PostResult postSync(Context context, String url, String version, AuthInfo authInfo, | ||
| HashMap<String, String> params, boolean useFormEncoding, | ||
| boolean background) { | ||
| ConnectNetworkHelper instance = getInstance(); | ||
|
|
||
| if (!background) { | ||
| setCallInProgress(url); | ||
| instance.showProgressDialog(context); | ||
| } | ||
|
|
||
| try { | ||
| HashMap<String, String> headers = new HashMap<>(); | ||
| RequestBody requestBody = buildPostFormHeaders(params, useFormEncoding, version, headers); | ||
|
|
||
| ModernHttpRequester requester = CommCareApplication.instance().buildHttpRequester( | ||
| context, | ||
| url, | ||
| ImmutableMultimap.of(), | ||
| headers, | ||
| requestBody, | ||
| null, | ||
| HTTPMethod.POST, | ||
| authInfo, | ||
| null, | ||
| false); | ||
|
|
||
| int responseCode = -1; | ||
| InputStream stream = null; | ||
| IOException exception = null; | ||
| try { | ||
| Response<ResponseBody> response = requester.makeRequest(); | ||
| responseCode = response.code(); | ||
| if (response.isSuccessful()) { | ||
| stream = requester.getResponseStream(response); | ||
| } else if (response.errorBody() != null) { | ||
| String error = response.errorBody().string(); | ||
| Logger.log("Netowrk Error", error); | ||
| } | ||
| } catch (IOException e) { | ||
| exception = e; | ||
| Logger.exception("Exception during POST", e); | ||
| } | ||
|
|
||
| instance.onFinishProcessing(context, background); | ||
|
|
||
| return new PostResult(responseCode, stream, exception); | ||
| } catch (Exception e) { | ||
| if (!background) { | ||
| setCallInProgress(null); | ||
| } | ||
| return new PostResult(-1, null, e); | ||
| } | ||
| } |
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.
🛠️ Refactor suggestion
Ensure prompt release of UI resources in error cases.
When an error occurs in postSync(), the app calls onFinishProcessing() only after the catch block. If a second error or other concurrency issues arise before that call, the progress dialog might remain stuck. Consider more robust finalization logic in each catch path.
| private void pruneOldJobs(List<ConnectJobRecord> existingList, List<ConnectJobRecord> jobs) { | ||
| Set<Integer> incomingJobIds = new HashSet<>(); | ||
| for (ConnectJobRecord job : jobs) { | ||
| incomingJobIds.add(job.getJobId()); | ||
| } | ||
|
|
||
| Vector<Integer> jobIdsToDelete = new Vector<>(); | ||
| Vector<Integer> appInfoIdsToDelete = new Vector<>(); | ||
| Vector<Integer> moduleIdsToDelete = new Vector<>(); | ||
| Vector<Integer> paymentUnitIdsToDelete = new Vector<>(); | ||
|
|
||
| for (ConnectJobRecord existing : existingList) { | ||
| if (!incomingJobIds.contains(existing.getJobId())) { | ||
| jobIdsToDelete.add(existing.getID()); | ||
| appInfoIdsToDelete.add(existing.getLearnAppInfo().getID()); | ||
| appInfoIdsToDelete.add(existing.getDeliveryAppInfo().getID()); | ||
|
|
||
| for (ConnectLearnModuleSummaryRecord module : existing.getLearnAppInfo().getLearnModules()) { | ||
| moduleIdsToDelete.add(module.getID()); | ||
| } | ||
|
|
||
| for (ConnectPaymentUnitRecord record : existing.getPaymentUnits()) { | ||
| paymentUnitIdsToDelete.add(record.getID()); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| deleteRecords(jobIdsToDelete, appInfoIdsToDelete, moduleIdsToDelete, paymentUnitIdsToDelete); | ||
| } |
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.
🛠️ Refactor suggestion
Null-safety check recommended for related entities.
Calls to existing.getLearnAppInfo().getID() or existing.getDeliveryAppInfo().getID() could throw a NullPointerException if getLearnAppInfo() or getDeliveryAppInfo() is null.
- appInfoIdsToDelete.add(existing.getLearnAppInfo().getID());
- appInfoIdsToDelete.add(existing.getDeliveryAppInfo().getID());
+ if (existing.getLearnAppInfo() != null) {
+ appInfoIdsToDelete.add(existing.getLearnAppInfo().getID());
+ }
+ if (existing.getDeliveryAppInfo() != null) {
+ appInfoIdsToDelete.add(existing.getDeliveryAppInfo().getID());
+ }📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| private void pruneOldJobs(List<ConnectJobRecord> existingList, List<ConnectJobRecord> jobs) { | |
| Set<Integer> incomingJobIds = new HashSet<>(); | |
| for (ConnectJobRecord job : jobs) { | |
| incomingJobIds.add(job.getJobId()); | |
| } | |
| Vector<Integer> jobIdsToDelete = new Vector<>(); | |
| Vector<Integer> appInfoIdsToDelete = new Vector<>(); | |
| Vector<Integer> moduleIdsToDelete = new Vector<>(); | |
| Vector<Integer> paymentUnitIdsToDelete = new Vector<>(); | |
| for (ConnectJobRecord existing : existingList) { | |
| if (!incomingJobIds.contains(existing.getJobId())) { | |
| jobIdsToDelete.add(existing.getID()); | |
| appInfoIdsToDelete.add(existing.getLearnAppInfo().getID()); | |
| appInfoIdsToDelete.add(existing.getDeliveryAppInfo().getID()); | |
| for (ConnectLearnModuleSummaryRecord module : existing.getLearnAppInfo().getLearnModules()) { | |
| moduleIdsToDelete.add(module.getID()); | |
| } | |
| for (ConnectPaymentUnitRecord record : existing.getPaymentUnits()) { | |
| paymentUnitIdsToDelete.add(record.getID()); | |
| } | |
| } | |
| } | |
| deleteRecords(jobIdsToDelete, appInfoIdsToDelete, moduleIdsToDelete, paymentUnitIdsToDelete); | |
| } | |
| private void pruneOldJobs(List<ConnectJobRecord> existingList, List<ConnectJobRecord> jobs) { | |
| Set<Integer> incomingJobIds = new HashSet<>(); | |
| for (ConnectJobRecord job : jobs) { | |
| incomingJobIds.add(job.getJobId()); | |
| } | |
| Vector<Integer> jobIdsToDelete = new Vector<>(); | |
| Vector<Integer> appInfoIdsToDelete = new Vector<>(); | |
| Vector<Integer> moduleIdsToDelete = new Vector<>(); | |
| Vector<Integer> paymentUnitIdsToDelete = new Vector<>(); | |
| for (ConnectJobRecord existing : existingList) { | |
| if (!incomingJobIds.contains(existing.getJobId())) { | |
| jobIdsToDelete.add(existing.getID()); | |
| if (existing.getLearnAppInfo() != null) { | |
| appInfoIdsToDelete.add(existing.getLearnAppInfo().getID()); | |
| } | |
| if (existing.getDeliveryAppInfo() != null) { | |
| appInfoIdsToDelete.add(existing.getDeliveryAppInfo().getID()); | |
| } | |
| for (ConnectLearnModuleSummaryRecord module : existing.getLearnAppInfo().getLearnModules()) { | |
| moduleIdsToDelete.add(module.getID()); | |
| } | |
| for (ConnectPaymentUnitRecord record : existing.getPaymentUnits()) { | |
| paymentUnitIdsToDelete.add(record.getID()); | |
| } | |
| } | |
| } | |
| deleteRecords(jobIdsToDelete, appInfoIdsToDelete, moduleIdsToDelete, paymentUnitIdsToDelete); | |
| } |
| public static void updateJobLearnProgress(Context context, ConnectJobRecord job) { | ||
| SqlStorage<ConnectJobRecord> jobStorage = ConnectDatabaseHelper.getConnectStorage(context, ConnectJobRecord.class); | ||
|
|
||
| job.setLastLearnUpdate(new Date()); | ||
|
|
||
| //Check for existing DB ID | ||
| Vector<ConnectJobRecord> existingJobs = | ||
| jobStorage.getRecordsForValues( | ||
| new String[]{ConnectJobRecord.META_JOB_ID}, | ||
| new Object[]{job.getJobId()}); | ||
|
|
||
| if (existingJobs.size() > 0) { | ||
| ConnectJobRecord existing = existingJobs.get(0); | ||
| existing.setCompletedLearningModules(job.getCompletedLearningModules()); | ||
| existing.setLastUpdate(new Date()); | ||
| jobStorage.write(existing); | ||
|
|
||
| //Also update learning and assessment records | ||
| storeLearningRecords(context, job.getLearnings(), job.getJobId(), true); | ||
| storeAssessments(context, job.getAssessments(), job.getJobId(), 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.
🛠️ Refactor suggestion
Ensure concurrency safety for 'updateJobLearnProgress' transactions.
updateJobLearnProgress() writes multiple records and updates the main job, but there's no explicit transaction handling here. If concurrency is possible (e.g., from multiple threads), consider adding concurrency guards or atomic DB transactions.
|
outdated and cretaed the new pr for that |
Product Description
Merging master to the initial branch
-->
Technical Summary
updating the latest code to the connectid branch
Feature Flag
Safety Assurance
Safety story
Automated test coverage
QA Plan
Labels and Review