-
Notifications
You must be signed in to change notification settings - Fork 22
Gateway Auth #499
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
base: main
Are you sure you want to change the base?
Gateway Auth #499
Conversation
How to use the Graphite Merge QueueAdd the label mergequeue to this PR to add it to the merge queue. You must have a Graphite account in order to use the merge queue. Sign up using this link. An organization admin has enabled the Graphite Merge Queue in this repository. Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue. |
|
Claude finished @tylerhawkes's task —— View job Code Review Complete ✓Reviewing PR #499: Gateway Auth implementation Todo List
Review FeedbackThis PR successfully introduces gateway authentication through 🟢 Strengths1. Security-Conscious Design
2. Clean API Design
3. Test Coverage
4. Proper FFI Integration
🟡 Areas for ImprovementSecurity Concerns1. Credential Value Not Actually Zeroed // Auth.kt:34-37
val charArray = value.toCharArray()
val credential = Credential(name, charArray, expiresAtSeconds)
// Zero the original string reference if possible, but since it's immutable, just return
return credentialIssue: The comment acknowledges the limitation but doesn't address it. The credential value remains in memory:
Recommendation: If credential security is critical:
Example improvement: companion object {
@JvmStatic
fun create(name: String, value: CharArray, expiresAtSeconds: Long): Credential {
val copiedArray = value.copyOf()
return Credential(name, copiedArray, expiresAtSeconds)
}
}
fun clear() {
valueCharArray.fill('\u0000')
}2. Exception Handling in Callbacks (Auth.kt:53-54) // "If onAuthRequired throws an exception, it will propagate and may crash the FFI layer"Issue: The documentation warns about crashes but doesn't enforce safe handling. Recommendation: Consider wrapping the FFI callback in a try-catch: fun toFfi(): FfiAuthCallback = object : FfiAuthCallback {
override suspend fun onAuthRequired(): FfiCredential = try {
Credential.toFfi(this@AuthCallback.onAuthRequired())
} catch (e: Exception) {
Log.e("AuthCallback", "Auth callback failed", e)
throw XMTPException("Authentication failed: ${e.message}", e)
}
}3. Cache Key Excludes Auth Details (Client.kt:74-75) fun toCacheKey(): String =
"${env.getUrl()}|$isSecure|${appVersion ?: "nil"}|${gatewayHost ?: "nil"}|${authCallback != null}"Issue: The cache key only checks
Recommendation: Either:
Android/Kotlin Best Practices4. Missing Proguard/R8 Rules Recommendation: Add proguard rules to prevent shrinking of FFI types: 5. Test Cleanup Missing (Auth.kt androidTest:46) handle.close()Issue: If the test fails before line 46, the handle leaks. The same issue exists if Recommendation: Use try-finally or @Test
fun testAuthHandle() = runBlocking {
AuthHandle().use { handle ->
val credential = Credential.create("handleName", "handleValue", 789L)
handle.set(credential)
val api = ClientOptions.Api(
env = XMTPEnvironment.DEV,
gatewayHost = "test.com",
authHandle = handle,
)
val client = Client.connectToApiBackend(api)
Assert.assertNotNull(client)
}
}6. Potential Memory Leak in Tests (Auth.kt androidTest:28-29, 44-45) Recommendation: Either:
Code Quality7. Inconsistent Nullable Handling (Client.kt:66-67) val authCallback: AuthCallback? = null,
val authHandle: AuthHandle? = null,Issue: Both can be provided simultaneously, but it's unclear which takes precedence or if this is an error. Recommendation:
init {
require(authCallback == null || authHandle == null) {
"Cannot provide both authCallback and authHandle"
}
}8. Backing Property Unnecessary (Auth.kt:72-73) internal val handle: FfiAuthHandle
get() = ffiHandleIssue: This getter just returns the same field. Consider exposing 9. Data Class Equals/HashCode Issue (Auth.kt:12-18) Recommendation: Override equals/hashCode or make it a regular class: override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is Credential) return false
return name == other.name &&
valueCharArray.contentEquals(other.valueCharArray) &&
expiresAtSeconds == other.expiresAtSeconds
}
override fun hashCode(): Int {
return 31 * (31 * name.hashCode() + valueCharArray.contentHashCode()) + expiresAtSeconds.hashCode()
}🔵 Minor Issues10. Typo in Comment (Client.kt:70-72) /**
* Cache key excluding auth details, as auth is connection-specific and handled via
* callbacks/handles. Connections with auth will use the callback/handle rather than cache
* invalidation.
*/The wording "rather than cache invalidation" is confusing. Clarify the intent. 11. Missing KDoc for FFI Methods (Auth.kt:41, 44, 59)
12. Test Assertions Could Be Stronger (AuthCredentialTest.kt:23, 33) Assert.assertTrue(e.message!!.contains("blank"))Issue: Force-unwrapping with Recommendation: Assert.assertTrue(e.message?.contains("blank") == true)📊 Test Coverage AssessmentGood Coverage:
Missing Coverage:
🎯 SummaryThis is a solid implementation that introduces authentication support cleanly. The main concerns are:
Overall, the code is well-structured and follows Kotlin conventions. With the security and caching issues addressed, this will be production-ready. |
fed46b8 to
aa75d63
Compare
Add Gateway Auth by wiring
AuthCallbackandAuthHandlethroughClientOptionsto FFI with contract version check 29Introduce Kotlin
Credential,AuthCallback, andAuthHandle, thread them throughClientOptionsto backend connection, and add FFI bindings with async trait calls, foreign futures, and checksum/version validation. Update generated native libraries and register new auth and message deletion callbacks in xmtpv3.kt.📍Where to Start
Start with FFI load/registration and contract/checksum checks in xmtpv3.kt, then follow
ClientOptionsusage in Client.kt, and the credential/callback/handle types in Auth.kt.Macroscope summarized fed46b8.