mirror of
https://github.com/msfjarvis/compose-lobsters
synced 2025-08-14 08:17:04 +05:30
feat(android): add a repository for extracting CSRF token
This commit is contained in:
parent
93d2397572
commit
c1f1d67bfa
7 changed files with 111 additions and 3 deletions
|
@ -66,7 +66,11 @@ dependencies {
|
|||
implementation(libs.androidx.work.runtime.ktx)
|
||||
implementation(libs.coil)
|
||||
implementation(libs.copydown)
|
||||
implementation(libs.jsoup)
|
||||
implementation(libs.kotlinx.collections.immutable)
|
||||
implementation(libs.kotlinx.coroutines.core)
|
||||
implementation(libs.sqldelight.extensions.coroutines)
|
||||
testImplementation(libs.kotest.assertions.core)
|
||||
testImplementation(libs.kotest.runner.junit5)
|
||||
testImplementation(libs.okhttp.mockwebserver)
|
||||
}
|
||||
|
|
|
@ -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.android.viewmodel
|
||||
|
||||
import dev.msfjarvis.claw.android.injection.IODispatcher
|
||||
import dev.msfjarvis.claw.api.injection.BaseUrl
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.withContext
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import org.jsoup.Jsoup
|
||||
|
||||
/** Helper for extracting CSRF token for authenticated requests to https://lobste.rs. */
|
||||
class CSRFRepository
|
||||
@Inject
|
||||
constructor(
|
||||
private val okHttpClient: OkHttpClient,
|
||||
@IODispatcher private val dispatcher: CoroutineDispatcher,
|
||||
@BaseUrl private val url: String,
|
||||
) {
|
||||
suspend fun extractToken(): String? {
|
||||
val request = Request.Builder().url(url).get().build()
|
||||
return withContext(dispatcher) {
|
||||
okHttpClient.newCall(request).execute().use { response ->
|
||||
val doc = Jsoup.parse(response.body?.string() ?: return@use null)
|
||||
val element = doc.select("meta[name=\"csrf-token\"]").first() ?: return@use null
|
||||
return@use element.attr("content")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* 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.android.viewmodel
|
||||
|
||||
import io.kotest.core.spec.Spec
|
||||
import io.kotest.core.spec.style.FunSpec
|
||||
import io.kotest.matchers.shouldBe
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.mockwebserver.Dispatcher
|
||||
import okhttp3.mockwebserver.MockResponse
|
||||
import okhttp3.mockwebserver.MockWebServer
|
||||
import okhttp3.mockwebserver.RecordedRequest
|
||||
|
||||
class CSRFRepositoryTest : FunSpec() {
|
||||
private val server = MockWebServer()
|
||||
|
||||
init {
|
||||
test("Correctly extracts CSRF token").config(coroutineTestScope = true) {
|
||||
val repo =
|
||||
CSRFRepository(
|
||||
OkHttpClient.Builder().build(),
|
||||
Dispatchers.Default,
|
||||
server.url("/").toString(),
|
||||
)
|
||||
repo.extractToken() shouldBe
|
||||
"OZWykgFemPVeOSNmB53-ccKXe458X7xCInO1-qzFU6nk_9RCSrSQqS9OPmA5_pyy8qD3IYAIZ7XfAM3gdhJpkQ"
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun beforeSpec(spec: Spec) {
|
||||
super.beforeSpec(spec)
|
||||
val dispatcher =
|
||||
object : Dispatcher() {
|
||||
override fun dispatch(request: RecordedRequest): MockResponse {
|
||||
return when (val path = request.path) {
|
||||
"/" ->
|
||||
MockResponse()
|
||||
.setResponseCode(200)
|
||||
.setBody(
|
||||
javaClass.classLoader!!
|
||||
.getResourceAsStream("csrf_page.html")
|
||||
.readAllBytes()
|
||||
.decodeToString(),
|
||||
)
|
||||
else -> error("Invalid path: $path")
|
||||
}
|
||||
}
|
||||
}
|
||||
server.dispatcher = dispatcher
|
||||
}
|
||||
}
|
5
android/src/test/resources/csrf_page.html
Normal file
5
android/src/test/resources/csrf_page.html
Normal file
File diff suppressed because one or more lines are too long
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright © 2021-2022 Harsh Shandilya.
|
||||
* Copyright © 2021-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.
|
||||
|
@ -13,6 +13,7 @@ import com.squareup.anvil.annotations.ContributesTo
|
|||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dev.msfjarvis.claw.api.LobstersApi
|
||||
import javax.inject.Qualifier
|
||||
import okhttp3.OkHttpClient
|
||||
import retrofit2.Converter
|
||||
import retrofit2.Retrofit
|
||||
|
@ -25,10 +26,11 @@ object ApiModule {
|
|||
fun provideRetrofit(
|
||||
client: OkHttpClient,
|
||||
converterFactories: Set<@JvmSuppressWildcards Converter.Factory>,
|
||||
@BaseUrl baseUrl: String,
|
||||
): Retrofit {
|
||||
return Retrofit.Builder()
|
||||
.client(client)
|
||||
.baseUrl(LobstersApi.BASE_URL)
|
||||
.baseUrl(baseUrl)
|
||||
.addConverterFactory(ApiResultConverterFactory)
|
||||
.addCallAdapterFactory(ApiResultCallAdapterFactory)
|
||||
.apply { converterFactories.forEach(this::addConverterFactory) }
|
||||
|
@ -39,4 +41,8 @@ object ApiModule {
|
|||
fun provideApi(retrofit: Retrofit): LobstersApi {
|
||||
return retrofit.create()
|
||||
}
|
||||
|
||||
@Provides @BaseUrl fun provideBaseUrl(): String = LobstersApi.BASE_URL
|
||||
}
|
||||
|
||||
@Qualifier @Retention(AnnotationRetention.RUNTIME) annotation class BaseUrl
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright © 2022 Harsh Shandilya.
|
||||
* 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.
|
||||
|
|
|
@ -77,6 +77,7 @@ napier = "io.github.aakira:napier:2.6.1"
|
|||
okhttp-bom = "com.squareup.okhttp3:okhttp-bom:4.10.0"
|
||||
okhttp-core = { module = "com.squareup.okhttp3:okhttp" }
|
||||
okhttp-loggingInterceptor = { module = "com.squareup.okhttp3:logging-interceptor" }
|
||||
okhttp-mockwebserver = { module = "com.squareup.okhttp3:mockwebserver" }
|
||||
retrofit = { module = "com.squareup.retrofit2:retrofit", version.ref = "retrofit" }
|
||||
retrofit-kotlinxSerializationConverter = "com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:0.8.0"
|
||||
sentry-bom = { module = "io.sentry:sentry-bom", version.ref = "sentry-sdk" }
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue