mirror of
https://github.com/msfjarvis/compose-lobsters
synced 2025-08-14 14:07:05 +05:30
refactor(api): import CSRF extraction from android
module
This commit is contained in:
parent
ddfa62f4fb
commit
1cb3eb6472
9 changed files with 73 additions and 97 deletions
9
api/src/main/kotlin/dev/msfjarvis/claw/api/CSRFToken.kt
Normal file
9
api/src/main/kotlin/dev/msfjarvis/claw/api/CSRFToken.kt
Normal 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)
|
|
@ -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"
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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> =
|
||||
|
|
|
@ -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"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"))
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
5
api/src/test/resources/csrf_page.html
Normal file
5
api/src/test/resources/csrf_page.html
Normal file
File diff suppressed because one or more lines are too long
Loading…
Add table
Add a link
Reference in a new issue