fix: address OAuth review findings (redirect_uri, binding, timeout, CRLF, DRY)
This commit is contained in:
@@ -1,6 +1,9 @@
|
||||
package ch.parano.myice.auth
|
||||
|
||||
import kotlinx.cinterop.ExperimentalForeignApi
|
||||
import kotlinx.coroutines.TimeoutCancellationException
|
||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
import kotlinx.coroutines.withTimeout
|
||||
import platform.AuthenticationServices.ASWebAuthenticationPresentationContextProvidingProtocol
|
||||
import platform.AuthenticationServices.ASWebAuthenticationSession
|
||||
import platform.Foundation.NSError
|
||||
@@ -10,53 +13,54 @@ import platform.UIKit.UIWindow
|
||||
import platform.UIKit.UIWindowScene
|
||||
import platform.darwin.NSObject
|
||||
import kotlin.coroutines.resume
|
||||
import kotlin.coroutines.suspendCoroutine
|
||||
|
||||
@OptIn(ExperimentalForeignApi::class)
|
||||
class IosOAuthClient : OAuthClient {
|
||||
|
||||
override fun redirectUri(): String = "myice://callback"
|
||||
|
||||
override suspend fun authenticate(loginUrl: String): String? = suspendCoroutine { continuation ->
|
||||
val nsUrl = NSURL.URLWithString(loginUrl) ?: run {
|
||||
continuation.resume(null)
|
||||
return@suspendCoroutine
|
||||
}
|
||||
|
||||
val session = ASWebAuthenticationSession(
|
||||
nsUrl,
|
||||
"myice",
|
||||
completionHandler = { callbackURL: NSURL?, error: NSError? ->
|
||||
if (error != null || callbackURL == null) {
|
||||
override suspend fun authenticate(loginUrl: String): String? = try {
|
||||
withTimeout(TIMEOUT_MS) {
|
||||
suspendCancellableCoroutine { continuation ->
|
||||
val nsUrl = NSURL.URLWithString(loginUrl) ?: run {
|
||||
continuation.resume(null)
|
||||
} else {
|
||||
val urlStr = callbackURL.absoluteString ?: ""
|
||||
val fragmentIndex = urlStr.indexOf("#")
|
||||
if (fragmentIndex < 0) {
|
||||
continuation.resume(null)
|
||||
} else {
|
||||
val fragment = urlStr.substring(fragmentIndex + 1)
|
||||
val params = fragment.split("&").associate { pair ->
|
||||
val idx = pair.indexOf("=")
|
||||
if (idx >= 0) pair.substring(0, idx) to pair.substring(idx + 1)
|
||||
else pair to ""
|
||||
return@suspendCancellableCoroutine
|
||||
}
|
||||
|
||||
val session = ASWebAuthenticationSession(
|
||||
nsUrl,
|
||||
"myice",
|
||||
completionHandler = { callbackURL: NSURL?, error: NSError? ->
|
||||
if (error != null || callbackURL == null) {
|
||||
continuation.resume(null)
|
||||
} else {
|
||||
val urlStr = callbackURL.absoluteString ?: ""
|
||||
val fragmentIndex = urlStr.indexOf("#")
|
||||
if (fragmentIndex < 0) {
|
||||
continuation.resume(null)
|
||||
} else {
|
||||
val fragment = urlStr.substring(fragmentIndex + 1)
|
||||
continuation.resume(parseAccessTokenFromFragment(fragment))
|
||||
}
|
||||
}
|
||||
continuation.resume(params["access_token"])
|
||||
}
|
||||
)
|
||||
|
||||
session.presentationContextProvider = object : NSObject(),
|
||||
ASWebAuthenticationPresentationContextProvidingProtocol {
|
||||
override fun presentationAnchorForWebAuthenticationSession(
|
||||
session: ASWebAuthenticationSession
|
||||
): UIWindow {
|
||||
return keyWindow()
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
session.presentationContextProvider = object : NSObject(),
|
||||
ASWebAuthenticationPresentationContextProvidingProtocol {
|
||||
override fun presentationAnchorForWebAuthenticationSession(
|
||||
session: ASWebAuthenticationSession
|
||||
): UIWindow {
|
||||
return keyWindow()
|
||||
continuation.invokeOnCancellation { session.cancel() }
|
||||
session.start()
|
||||
}
|
||||
}
|
||||
|
||||
session.start()
|
||||
} catch (e: TimeoutCancellationException) {
|
||||
null
|
||||
}
|
||||
|
||||
private fun keyWindow(): UIWindow {
|
||||
@@ -64,4 +68,8 @@ class IosOAuthClient : OAuthClient {
|
||||
val windowScene = scenes.firstOrNull { it is UIWindowScene } as? UIWindowScene
|
||||
return (windowScene?.windows?.firstOrNull() as? UIWindow) ?: UIWindow()
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val TIMEOUT_MS = 5L * 60 * 1000
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user