Skip to content

Conversation

@phobos665
Copy link
Contributor

@phobos665 phobos665 commented Jan 13, 2026

Description

  • Migrates the Auth-related logic to Kotlin, removing the requirement for auth-related functionality to use GOGDL & Python.

Implementation Details:

This is mostly just storing/retrieving details from the JSON file we store the credentials in and running REST API requests to the GOG auth service.

Summary by CodeRabbit

  • Bug Fixes

    • More reliable GOG login with HTTP-based token handling, clearer error handling, and automatic refresh of expired credentials.
  • New Features

    • Persistent local storage of GOG credentials and a check for existing stored credentials.
    • Utility to extract authorization codes from pasted URLs or plain input.
  • Tests

    • Added comprehensive tests for authentication, storage, refresh, validation, and code extraction.
  • Chores

    • Updated GOG authentication constants and login flow.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Jan 13, 2026

📝 Walkthrough

Walkthrough

Replaces the GOGDL/command-based auth with an HTTP OAuth2 flow using OkHttp; exchanges and refreshes tokens, persists credentials in gog_auth.json, exposes token retrieval/validation APIs (including hasStoredCredentials() and public extractCodeFromInput()), and adds tests for success, error, refresh, and code extraction.

Changes

Cohort / File(s) Summary
OAuth2 HTTP Authentication
app/src/main/java/app/gamenative/service/gog/GOGAuthManager.kt
Replaces GOGDL-based flow with HTTP OAuth2 token exchange and refresh via OkHttp; adds coroutine IO, HTTP error handling, JSON parsing, expiration checks, getGameCredentials() and refreshCredentials(), hasStoredCredentials(), makes extractCodeFromInput() public, and persists tokens/metadata to gog_auth.json.
Constants
app/src/main/java/app/gamenative/service/gog/GOGConstants.kt
Adds GOG_CLIENT_SECRET, updates GOG_AUTH_LOGIN_URL (from layout=client2layout=client), and annotates GOG_CLIENT_ID as public data.
Tests (new)
app/src/test/java/app/gamenative/service/gog/GOGAuthManagerTest.kt
Adds Robolectric/MockWebServer test suite covering: successful code exchange, error response handling, stored credential read/write, expired-token refresh flow, validation, and multiple extractCodeFromInput() input formats.
Build (tests)
app/build.gradle.kts
Adds test dependencies: org.json:json:20231013 and com.squareup.okhttp3:mockwebserver:5.1.0 for unit/integration tests.

Sequence Diagram(s)

sequenceDiagram
    participant App
    participant HTTP as OkHttp Client
    participant GOG as GOG OAuth Server
    participant FS as File Storage

    App->>HTTP: GET token endpoint (clientId, clientSecret, code)
    HTTP->>GOG: HTTP request
    GOG-->>HTTP: JSON {access_token, refresh_token, expires_in, user_id}
    HTTP-->>App: parsed token payload
    App->>FS: write/update `gog_auth.json` (tokens, loginTime, expires_in)

    Note over App,FS: On credential use
    App->>FS: read `gog_auth.json`
    FS-->>App: stored tokens + loginTime
    App->>App: check expiration (loginTime + expires_in)
    alt expired
        App->>HTTP: GET refresh endpoint (refresh_token)
        HTTP->>GOG: HTTP request
        GOG-->>HTTP: JSON {access_token, refresh_token, expires_in}
        HTTP-->>App: parsed refreshed tokens
        App->>FS: update `gog_auth.json`
    end
    App-->>App: return valid credentials
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • Gog integration utkarsh #393: Replaces GOGDL-based GOGAuthManager with an HTTP/OkHttp token exchange and file-based storage; high overlap/conflict with this PR's auth manager changes.

Poem

🐰 I hopped from CLI to HTTP bright,
Tokens tucked safe in JSON at night,
I nibble refreshes when expiry draws near,
I sniff out codes both plain and clear,
Hooray — secure hops and auth in flight!

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 34.78% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly and clearly summarizes the main change: migrating GOG authentication logic from GOGDL/Python to Kotlin implementation, which is the core focus of all changes across the modified files.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
app/src/main/java/app/gamenative/service/gog/GOGAuthManager.kt (1)

284-293: Potential race condition on concurrent file access.

If getGameCredentials is called concurrently for different games, both calls read the auth file, modify authJson, and write back. The second write could overwrite changes from the first. Consider using a mutex or synchronized file access.

🔧 Suggested approach using Mutex

Add a mutex at the class level:

private val authFileMutex = kotlinx.coroutines.sync.Mutex()

Then wrap the read-modify-write operations:

+            authFileMutex.withLock {
                 // Store the new game-specific credentials
                 json.put("loginTime", System.currentTimeMillis() / 1000.0)
                 authJson.put(clientId, json)

                 // Write updated auth file
-                authFile.writeText(authJson.toString(2))
+                withContext(Dispatchers.IO) {
+                    authFile.writeText(authJson.toString(2))
+                }
+            }
🤖 Fix all issues with AI agents
In @app/src/main/java/app/gamenative/service/gog/GOGAuthManager.kt:
- Around line 134-136: The blocking call
authFile.writeText(authData.toString(2)) in GOGAuthManager should be moved onto
the IO dispatcher; wrap that write inside withContext(Dispatchers.IO) {
authFile.writeText(...) } (or perform the write in a
CoroutineScope(Dispatchers.IO).launch) and ensure the enclosing function is
suspend or dispatches appropriately and that kotlinx.coroutines.Dispatchers and
withContext are imported so file I/O doesn’t run on the main thread.
- Around line 157-160: The file read is performed on the calling thread in
GOGAuthManager where authFile.readText() and JSONObject parsing occur; wrap the
blocking read in withContext(Dispatchers.IO) to perform IO on the IO dispatcher
and return the file content to the caller for JSON parsing. Update the code
surrounding authFile.readText() (referencing authFile, authConfigPath, and
authJson) to call withContext(Dispatchers.IO) { authFile.readText() } (importing
kotlinx.coroutines.Dispatchers and withContext) so only the blocking read runs
on IO while JSON construction happens off that dispatcher.
🧹 Nitpick comments (2)
app/src/main/java/app/gamenative/service/gog/GOGConstants.kt (1)

27-29: Public OAuth2 client credentials - static analysis false positive.

The Gitleaks alert is a false positive. GOG's OAuth2 flow uses publicly known client credentials embedded in the official GOG Galaxy desktop client. This is standard practice for OAuth2 "public clients" (native/desktop apps) where the client secret cannot be kept confidential. The comment correctly documents this.

However, consider adding a more detailed comment explaining why these are safe to expose, to prevent future confusion or re-flagging:

📝 Suggested documentation improvement
-    // GOG Client ID for authentication - These are public and not sensitive information.
+    // GOG Client ID and Secret for authentication.
+    // These are public values extracted from the GOG Galaxy client and are intentionally
+    // non-secret for OAuth2 public client flows (native apps cannot protect secrets).
     const val GOG_CLIENT_ID = "46899977096215655"
     const val GOG_CLIENT_SECRET = "9d85c43b1482497dbbce61f6e4aa173a433796eeae2ca8c5f6129f2dc4de46d9"
app/src/main/java/app/gamenative/service/gog/GOGAuthManager.kt (1)

82-95: Potential issue: Response body consumed twice on error path.

On line 87, response.body?.string() is called to get the error body. However, OkHttp response bodies can only be consumed once. If you later tried to use the body again, it would fail. In this specific code path it's fine since you return immediately, but this pattern is fragile.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f9d067b and 6c211f9.

📒 Files selected for processing (2)
  • app/src/main/java/app/gamenative/service/gog/GOGAuthManager.kt
  • app/src/main/java/app/gamenative/service/gog/GOGConstants.kt
🧰 Additional context used
🧬 Code graph analysis (1)
app/src/main/java/app/gamenative/service/gog/GOGAuthManager.kt (1)
app/src/main/java/app/gamenative/service/gog/GOGService.kt (2)
  • getStoredCredentials (119-121)
  • hasStoredCredentials (114-116)
🪛 Gitleaks (8.30.0)
app/src/main/java/app/gamenative/service/gog/GOGConstants.kt

[high] 29-29: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

🔇 Additional comments (7)
app/src/main/java/app/gamenative/service/gog/GOGConstants.kt (1)

34-35: LGTM!

The OAuth authorization URL is correctly constructed with the necessary parameters. The layout=client parameter aligns with the standard GOG Galaxy client authentication flow.

app/src/main/java/app/gamenative/service/gog/GOGAuthManager.kt (6)

27-30: LGTM!

The singleton OkHttpClient with 30-second timeouts is appropriate for authentication operations. OkHttp clients are designed to be shared across requests for connection pooling efficiency.


169-183: LGTM!

The token expiration logic is correct. The recursive call to getStoredCredentials after refresh is safe since refreshed tokens won't immediately expire, preventing infinite recursion.


352-416: Consistent file I/O pattern - same concerns apply.

The refresh logic is correct. The same file I/O dispatcher concerns mentioned earlier apply to this function as well (lines 363, 408).


418-433: LGTM!

The URL code extraction logic correctly handles both direct authorization codes and full redirect URLs containing the code parameter.


310-333: LGTM!

The validation logic cleanly delegates to getStoredCredentials, which handles token refresh automatically. The error handling appropriately distinguishes between "no credentials" (returns false) and actual failures (returns Result.failure).


338-350: LGTM!

The logout implementation correctly handles both cases: existing file deletion and non-existent file. Consider making this a suspend fun with withContext(Dispatchers.IO) for consistency with other file operations, but the current synchronous approach is acceptable for this simple operation.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
app/src/main/java/app/gamenative/service/gog/GOGAuthManager.kt (2)

226-229: File I/O not wrapped in Dispatchers.IO - potential ANR.

authFile.readText() on line 228 performs blocking I/O on the caller's coroutine context. Other methods like authenticateWithCode and getStoredCredentials correctly use withContext(Dispatchers.IO) for file operations.

🐛 Proposed fix
             // Read auth file
-            val authContent = authFile.readText()
+            val authContent = withContext(Dispatchers.IO) { authFile.readText() }
             val authJson = JSONObject(authContent)

290-299: File write inside use block not on IO dispatcher.

The file write at line 295 (authFile.writeText(...)) performs blocking I/O within the response processing block but outside any Dispatchers.IO context. This should be wrapped for consistency and to avoid blocking the coroutine.

🐛 Proposed fix
                 // Store the new game-specific credentials
                 json.put("loginTime", System.currentTimeMillis() / 1000.0)
                 authJson.put(clientId, json)
 
                 // Write updated auth file
-                authFile.writeText(authJson.toString(2))
+                withContext(Dispatchers.IO) {
+                    authFile.writeText(authJson.toString(2))
+                }
 
                 Timber.i("Successfully obtained game-specific token for clientId: $clientId")
                 json
🤖 Fix all issues with AI agents
In @app/src/main/java/app/gamenative/service/gog/GOGAuthManager.kt:
- Around line 368-370: The file read is happening on the calling coroutine
context (authFile.readText()) inside GOGAuthManager; wrap the blocking I/O in
withContext(Dispatchers.IO) so the read and JSONObject creation occur off the
main thread. Specifically, move the authFile.readText() call into a
withContext(Dispatchers.IO) block and assign its result to authContent there
before constructing authJson, ensuring the coroutine uses Dispatchers.IO for
file I/O.
- Around line 264-271: The code in GOGAuthManager that builds the request URL
for the game-specific token is using a hardcoded "https://auth.gog.com/token"
which prevents tests from swapping in a MockWebServer; update the builder to use
the existing configurable tokenUrl property (the same tokenUrl used elsewhere)
instead of the hardcoded string, e.g. call tokenUrl.toHttpUrl().newBuilder() and
then add the same query parameters (client_id, client_secret, grant_type,
refresh_token) so tests can point tokenUrl to a MockWebServer endpoint while
preserving the current parameter construction in the method that requests the
game-specific token.
🧹 Nitpick comments (5)
app/src/main/java/app/gamenative/service/gog/GOGAuthManager.kt (3)

86-99: Response body consumed twice risk - potential issue with error handling.

If response.isSuccessful is false on line 90, you read response.body?.string() for the error body. However, if somehow the code continued (which it doesn't due to return), you'd have an issue. The current flow is correct, but there's a subtle issue: on success, if response.body is null (rare but possible), you return failure, but the error message won't indicate why.

Consider adding clarity to the empty response error:

💡 Suggested improvement
-                val responseBody = response.body?.string() ?: return Result.failure(Exception("Empty response"))
+                val responseBody = response.body?.string() ?: return Result.failure(Exception("Empty response body from auth server"))

40-43: Consider making hasStoredCredentials a suspend function.

This performs a file existence check on the calling thread. While fast, for consistency with the stated goal of running file operations off the IO thread, consider making this a suspend function or documenting that callers should invoke it from appropriate contexts.


430-445: URL-decoding is technically RFC-compliant but not required for GOG.

RFC 6749 specifies that authorization code parameters are transmitted via URL-encoded query strings, which suggests URL-decoding is appropriate. However, GOG's authorization codes are opaque, URL-safe strings that don't contain special characters requiring decoding. While adding URLDecoder.decode(cleanCode, "UTF-8") would be more RFC-strict, it's unnecessary for GOG's actual behavior and won't prevent authentication failures. The current implementation is sufficient.

app/src/test/java/app/gamenative/service/gog/GOGAuthManagerTest.kt (2)

47-54: createTempDir is deprecated - use kotlin.io.path.createTempDirectory.

The createTempDir function is deprecated in Kotlin. Consider using the newer kotlin.io.path.createTempDirectory API.

♻️ Proposed fix
+import kotlin.io.path.createTempDirectory
+
     @Before
     fun setUp() {
         closeable = MockitoAnnotations.openMocks(this)
         mockWebServer = MockWebServer()
         mockWebServer.start()
-        tempDir = createTempDir("gogtest")
+        tempDir = createTempDirectory("gogtest").toFile()
         `when`(context.filesDir).thenReturn(tempDir)
     }

239-251: Consider adding tests for getGameCredentials, clearStoredCredentials, and hasStoredCredentials.

The test suite covers the main authentication flows but doesn't include tests for:

  • getGameCredentials - game-specific token retrieval
  • clearStoredCredentials - logout functionality
  • hasStoredCredentials - credential existence check

Note: Testing getGameCredentials would require fixing the hardcoded token URL issue flagged in the main file.

Would you like me to generate test cases for these methods?

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6c211f9 and 77e0698.

📒 Files selected for processing (2)
  • app/src/main/java/app/gamenative/service/gog/GOGAuthManager.kt
  • app/src/test/java/app/gamenative/service/gog/GOGAuthManagerTest.kt
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-09-19T17:13:01.017Z
Learnt from: utkarshdalal
Repo: utkarshdalal/GameNative PR: 159
File: app/src/main/java/app/gamenative/ui/screen/library/LibraryAppScreen.kt:136-136
Timestamp: 2025-09-19T17:13:01.017Z
Learning: In LibraryAppScreen.kt, the user prefers to use runBlocking to maintain synchronous APIs when underlying methods have been converted to suspend functions, rather than refactoring all calling code to be async. This approach prevents UI breakage and maintains API compatibility. The user confirmed this is acceptable when performance is not a concern.

Applied to files:

  • app/src/main/java/app/gamenative/service/gog/GOGAuthManager.kt
📚 Learning: 2025-09-19T17:07:27.941Z
Learnt from: utkarshdalal
Repo: utkarshdalal/GameNative PR: 159
File: app/src/main/java/app/gamenative/service/DownloadService.kt:6-6
Timestamp: 2025-09-19T17:07:27.941Z
Learning: In app/src/main/java/app/gamenative/service/DownloadService.kt, the getSizeFromStoreDisplay() function uses runBlocking to call SteamService.getDownloadableDepots() because the latter was converted from synchronous to suspend in this PR. The user confirmed the previous synchronous implementation worked fine, and if performance is acceptable, keeping runBlocking is a valid approach.

Applied to files:

  • app/src/main/java/app/gamenative/service/gog/GOGAuthManager.kt
🧬 Code graph analysis (1)
app/src/main/java/app/gamenative/service/gog/GOGAuthManager.kt (1)
app/src/main/java/app/gamenative/service/gog/GOGService.kt (2)
  • getStoredCredentials (119-121)
  • hasStoredCredentials (114-116)
🔇 Additional comments (5)
app/src/main/java/app/gamenative/service/gog/GOGAuthManager.kt (1)

27-34: LGTM - HTTP client configuration with reasonable timeouts.

The OkHttpClient setup with 30-second connect and read timeouts is appropriate for network operations. The internal tokenUrl field for testing is a clean approach.

app/src/test/java/app/gamenative/service/gog/GOGAuthManagerTest.kt (4)

97-119: LGTM - Failure test case correctly validates error handling.

The test properly validates that HTTP errors are propagated with the response body included in the error message.


121-139: LGTM - Stored credentials test validates happy path.

The test correctly sets up non-expired credentials and verifies retrieval.


141-182: LGTM - Refresh flow test is comprehensive.

The test correctly validates the token refresh mechanism when credentials expire.


211-237: LGTM - Code extraction tests cover all edge cases.

The tests comprehensively validate URL parsing with various parameter combinations and plain code input.

Comment on lines 264 to +271
// Request game-specific token using Galaxy's refresh token
Timber.d("Requesting game-specific token for clientId: $clientId")
val tokenUrl = "https://auth.gog.com/token?client_id=$clientId&client_secret=$clientSecret&grant_type=refresh_token&refresh_token=$refreshToken"
val tokenUrl = "https://auth.gog.com/token".toHttpUrl().newBuilder()
.addQueryParameter("client_id", clientId)
.addQueryParameter("client_secret", clientSecret)
.addQueryParameter("grant_type", "refresh_token")
.addQueryParameter("refresh_token", refreshToken)
.build()
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Hardcoded token URL prevents testing with MockWebServer.

This method uses a hardcoded "https://auth.gog.com/token" instead of the configurable tokenUrl property used elsewhere. This makes the method untestable with MockWebServer.

♻️ Proposed fix for consistency
             // Request game-specific token using Galaxy's refresh token
             Timber.d("Requesting game-specific token for clientId: $clientId")
-            val tokenUrl = "https://auth.gog.com/token".toHttpUrl().newBuilder()
+            val gameTokenUrl = tokenUrl.toHttpUrl().newBuilder()
                 .addQueryParameter("client_id", clientId)
                 .addQueryParameter("client_secret", clientSecret)
                 .addQueryParameter("grant_type", "refresh_token")
                 .addQueryParameter("refresh_token", refreshToken)
                 .build()
 
             val request = okhttp3.Request.Builder()
-                .url(tokenUrl)
+                .url(gameTokenUrl)
                 .get()
                 .build()
📝 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.

Suggested change
// Request game-specific token using Galaxy's refresh token
Timber.d("Requesting game-specific token for clientId: $clientId")
val tokenUrl = "https://auth.gog.com/token?client_id=$clientId&client_secret=$clientSecret&grant_type=refresh_token&refresh_token=$refreshToken"
val tokenUrl = "https://auth.gog.com/token".toHttpUrl().newBuilder()
.addQueryParameter("client_id", clientId)
.addQueryParameter("client_secret", clientSecret)
.addQueryParameter("grant_type", "refresh_token")
.addQueryParameter("refresh_token", refreshToken)
.build()
// Request game-specific token using Galaxy's refresh token
Timber.d("Requesting game-specific token for clientId: $clientId")
val gameTokenUrl = tokenUrl.toHttpUrl().newBuilder()
.addQueryParameter("client_id", clientId)
.addQueryParameter("client_secret", clientSecret)
.addQueryParameter("grant_type", "refresh_token")
.addQueryParameter("refresh_token", refreshToken)
.build()
val request = okhttp3.Request.Builder()
.url(gameTokenUrl)
.get()
.build()
🤖 Prompt for AI Agents
In @app/src/main/java/app/gamenative/service/gog/GOGAuthManager.kt around lines
264 - 271, The code in GOGAuthManager that builds the request URL for the
game-specific token is using a hardcoded "https://auth.gog.com/token" which
prevents tests from swapping in a MockWebServer; update the builder to use the
existing configurable tokenUrl property (the same tokenUrl used elsewhere)
instead of the hardcoded string, e.g. call tokenUrl.toHttpUrl().newBuilder() and
then add the same query parameters (client_id, client_secret, grant_type,
refresh_token) so tests can point tokenUrl to a MockWebServer endpoint while
preserving the current parameter construction in the method that requests the
game-specific token.

Comment on lines +368 to +370
// Read current credentials
val authContent = authFile.readText()
val authJson = JSONObject(authContent)
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

File I/O not wrapped in Dispatchers.IO.

The file read at line 369 should be wrapped in withContext(Dispatchers.IO) for consistency with other methods and to prevent potential ANR issues.

🐛 Proposed fix
             // Read current credentials
-            val authContent = authFile.readText()
+            val authContent = withContext(Dispatchers.IO) { authFile.readText() }
             val authJson = JSONObject(authContent)
📝 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.

Suggested change
// Read current credentials
val authContent = authFile.readText()
val authJson = JSONObject(authContent)
// Read current credentials
val authContent = withContext(Dispatchers.IO) { authFile.readText() }
val authJson = JSONObject(authContent)
🤖 Prompt for AI Agents
In @app/src/main/java/app/gamenative/service/gog/GOGAuthManager.kt around lines
368 - 370, The file read is happening on the calling coroutine context
(authFile.readText()) inside GOGAuthManager; wrap the blocking I/O in
withContext(Dispatchers.IO) so the read and JSONObject creation occur off the
main thread. Specifically, move the authFile.readText() call into a
withContext(Dispatchers.IO) block and assign its result to authContent there
before constructing authJson, ensuring the coroutine uses Dispatchers.IO for
file I/O.

Comment on lines +411 to +414
// Update credentials in auth file
tokenJson.put("loginTime", System.currentTimeMillis() / 1000.0)
authJson.put(clientId, tokenJson)
authFile.writeText(authJson.toString(2))
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

File write not on IO dispatcher.

Line 414 performs blocking file I/O without Dispatchers.IO wrapping.

🐛 Proposed fix
             // Update credentials in auth file
             tokenJson.put("loginTime", System.currentTimeMillis() / 1000.0)
             authJson.put(clientId, tokenJson)
-            authFile.writeText(authJson.toString(2))
+            withContext(Dispatchers.IO) {
+                authFile.writeText(authJson.toString(2))
+            }
📝 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.

Suggested change
// Update credentials in auth file
tokenJson.put("loginTime", System.currentTimeMillis() / 1000.0)
authJson.put(clientId, tokenJson)
authFile.writeText(authJson.toString(2))
// Update credentials in auth file
tokenJson.put("loginTime", System.currentTimeMillis() / 1000.0)
authJson.put(clientId, tokenJson)
withContext(Dispatchers.IO) {
authFile.writeText(authJson.toString(2))
}

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
app/build.gradle.kts (1)

86-86: Address the deprecated resourceConfigurations API flagged by pipeline.

The pipeline warning indicates resourceConfigurations is deprecated. Migrate to the recommended androidResources.localeFilters API.

Proposed fix
-        resourceConfigurations += listOf(
+        androidResources.localeFilters += listOf(
             "en",      // English (default)
             "da",      // Danish
             "pt-rBR",  // Portuguese (Brazilian)
             "zh-rTW",  // Traditional Chinese
             "zh-rCN",  // Simplified Chinese
             "fr",      // French
             "de",      // German
             "uk",      // Ukrainian
             "it",      // Italian
             // TODO: Add more languages here using the ISO 639-1 locale code with regional qualifiers (e.g., "pt-rPT" for European Portuguese)
         )
🤖 Fix all issues with AI agents
In @app/build.gradle.kts:
- Around line 297-298: Replace the hardcoded test dependencies
testImplementation("org.json:json:20231013") and
testImplementation("com.squareup.okhttp3:mockwebserver:5.1.0") with
version-catalog references (e.g., use libs.json-org and libs.mockwebserver) and
add the corresponding entries to the version catalog: add versions json-org =
"20231013" and mockwebserver = "5.1.0" under [versions], and libraries json-org
= { module = "org.json:json", version.ref = "json-org" } and mockwebserver = {
module = "com.squareup.okhttp3:mockwebserver", version.ref = "mockwebserver" }
under [libraries] so the app/build.gradle.kts testImplementation calls reference
the catalog instead of hardcoded strings.
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 77e0698 and 918aa10.

📒 Files selected for processing (1)
  • app/build.gradle.kts
🧰 Additional context used
🪛 GitHub Actions: Pull Request build check
app/build.gradle.kts

[warning] 86-86: Deprecated Gradle feature used: 'resourceConfigurations: MutableSet' is deprecated. For language resource configurations in applications, use androidResources.localeFilters.

Comment on lines +297 to +298
testImplementation("org.json:json:20231013")
testImplementation("com.squareup.okhttp3:mockwebserver:5.1.0")
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# First, let's look at the app/build.gradle.kts file around lines 297-298
head -310 app/build.gradle.kts | tail -30

Repository: utkarshdalal/GameNative

Length of output: 1425


🏁 Script executed:

# Check if libs.versions.toml exists and examine its structure
find . -name "libs.versions.toml" -o -name "gradle.versions.toml"

Repository: utkarshdalal/GameNative

Length of output: 94


🏁 Script executed:

# Get a broader view of the build.gradle.kts to understand dependency patterns
grep -n "testImplementation\|implementation" app/build.gradle.kts | head -30

Repository: utkarshdalal/GameNative

Length of output: 1604


🏁 Script executed:

# Examine the libs.versions.toml structure
cat ./gradle/libs.versions.toml

Repository: utkarshdalal/GameNative

Length of output: 12001


🏁 Script executed:

# Search for any okhttp references in gradle files
rg -i "okhttp" --type gradle --type toml

Repository: utkarshdalal/GameNative

Length of output: 511


Add hardcoded test dependencies to version catalog for consistency.

The project uses the libs.* version catalog pattern for dependency management. The new test dependencies should follow this pattern instead of using hardcoded strings.

Additionally, org.json:json:20231013 is not currently in the version catalog and needs to be added. The mockwebserver version (5.1.0) aligns with the OkHttp version already defined in the catalog, so there's no compatibility concern.

Update gradle/libs.versions.toml:

Version catalog additions
[versions]
json-org = "20231013"
mockwebserver = "5.1.0"

[libraries]
json-org = { module = "org.json:json", version.ref = "json-org" }
mockwebserver = { module = "com.squareup.okhttp3:mockwebserver", version.ref = "mockwebserver" }

Then in app/build.gradle.kts:

Dependency declarations
-    testImplementation("org.json:json:20231013")
-    testImplementation("com.squareup.okhttp3:mockwebserver:5.1.0")
+    testImplementation(libs.json.org)
+    testImplementation(libs.mockwebserver)
🤖 Prompt for AI Agents
In @app/build.gradle.kts around lines 297 - 298, Replace the hardcoded test
dependencies testImplementation("org.json:json:20231013") and
testImplementation("com.squareup.okhttp3:mockwebserver:5.1.0") with
version-catalog references (e.g., use libs.json-org and libs.mockwebserver) and
add the corresponding entries to the version catalog: add versions json-org =
"20231013" and mockwebserver = "5.1.0" under [versions], and libraries json-org
= { module = "org.json:json", version.ref = "json-org" } and mockwebserver = {
module = "com.squareup.okhttp3:mockwebserver", version.ref = "mockwebserver" }
under [libraries] so the app/build.gradle.kts testImplementation calls reference
the catalog instead of hardcoded strings.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant