refactor(api): import CSRF extraction from android module

This commit is contained in:
Harsh Shandilya 2023-09-14 00:44:13 +05:30
parent ddfa62f4fb
commit 1cb3eb6472
No known key found for this signature in database
9 changed files with 73 additions and 97 deletions

View file

@ -0,0 +1,9 @@
/*
* Copyright © 2022-2023 Harsh Shandilya.
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
* https://opensource.org/licenses/MIT.
*/
package dev.msfjarvis.claw.api
@JvmInline value class CSRFToken(val value: String)

View file

@ -29,6 +29,8 @@ interface LobstersApi {
@GET("~{username}.json")
suspend fun getUser(@Path("username") username: String): ApiResult<User, Unit>
@GET("/") suspend fun getCSRFToken(): ApiResult<CSRFToken, Unit>
companion object {
const val BASE_URL = "https://lobste.rs"
}

View file

@ -0,0 +1,36 @@
/*
* Copyright © 2023 Harsh Shandilya.
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
* https://opensource.org/licenses/MIT.
*/
package dev.msfjarvis.claw.api.converters
import dev.msfjarvis.claw.api.CSRFToken
import dev.msfjarvis.claw.api.LobstersApi
import java.lang.reflect.Type
import okhttp3.ResponseBody
import org.jsoup.Jsoup
import retrofit2.Converter
import retrofit2.Retrofit
object CSRFTokenConverter : Converter<ResponseBody, CSRFToken> {
override fun convert(value: ResponseBody): CSRFToken {
val token =
Jsoup.parse(value.string(), LobstersApi.BASE_URL)
.select("meta[name=\"csrf-token\"]")
.first()!!
.attr("content")
return CSRFToken(token)
}
object Factory : Converter.Factory() {
override fun responseBodyConverter(
type: Type,
annotations: Array<out Annotation>,
retrofit: Retrofit,
): Converter<ResponseBody, CSRFToken> {
return CSRFTokenConverter
}
}
}

View file

@ -16,6 +16,7 @@ import dagger.multibindings.IntKey
import dagger.multibindings.IntoMap
import dev.msfjarvis.claw.api.LobstersApi
import dev.msfjarvis.claw.api.LobstersSearchApi
import dev.msfjarvis.claw.api.converters.CSRFTokenConverter
import dev.msfjarvis.claw.api.converters.SearchConverter
import javax.inject.Qualifier
import okhttp3.OkHttpClient
@ -81,6 +82,11 @@ object RetrofitModule {
@IntoMap
fun provideApiResultCallAdapter(): CallAdapter.Factory = ApiResultCallAdapterFactory
@Provides
@IntKey(Int.MAX_VALUE)
@IntoMap
fun provideCSRFTokenConverter(): Converter.Factory = CSRFTokenConverter.Factory
@Provides
@SearchApi
fun provideConverters(): List<@JvmSuppressWildcards Converter.Factory> =

View file

@ -49,4 +49,14 @@ class ApiTest {
assertIs<Success<User>>(user)
assertThat(user.value.username).isEqualTo("msfjarvis")
}
@Test
fun `retrieve CSRF token`() = runTest {
val token = api.getCSRFToken()
assertIs<Success<CSRFToken>>(token)
assertThat(token.value.value)
.isEqualTo(
"oLI2VtS7LbkvxzGZQXgvl3E88RSwOw38Z_nlkxTk5r9JUznOv7sS8BeV_8h-jmI3aMJBh1mdRz4ckl8ItW3tlA"
)
}
}

View file

@ -9,6 +9,7 @@ package dev.msfjarvis.claw.api
import com.slack.eithernet.ApiResult.Companion.success
import com.slack.eithernet.test.EitherNetController
import com.slack.eithernet.test.enqueue
import dev.msfjarvis.claw.api.converters.CSRFTokenConverter
import dev.msfjarvis.claw.model.LobstersPost
import dev.msfjarvis.claw.model.LobstersPostDetails
import dev.msfjarvis.claw.model.User
@ -16,6 +17,8 @@ import dev.msfjarvis.claw.util.TestUtils.getResource
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonNamingStrategy
import okhttp3.MediaType
import okhttp3.ResponseBody
@OptIn(ExperimentalSerializationApi::class)
class ApiWrapper(controller: EitherNetController<LobstersApi>) {
@ -35,5 +38,12 @@ class ApiWrapper(controller: EitherNetController<LobstersApi>) {
controller.enqueue(LobstersApi::getHottestPosts) { success(hottest) }
controller.enqueue(LobstersApi::getPostDetails) { success(postDetails) }
controller.enqueue(LobstersApi::getUser) { success(user) }
controller.enqueue(LobstersApi::getCSRFToken) {
success(
CSRFTokenConverter.convert(
ResponseBody.create(MediaType.get("text/html"), getResource("search_chatgpt_page.html"))
)
)
}
}
}

File diff suppressed because one or more lines are too long