Skip to content

Commit

Permalink
Digest is supported alongside the Basic method of authentication for …
Browse files Browse the repository at this point in the history
…WebDav.

Upping versionCode to 94
  • Loading branch information
Dima-Android committed Aug 29, 2024
1 parent a5d8549 commit 561a4f5
Show file tree
Hide file tree
Showing 9 changed files with 83 additions and 96 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import okhttp3.Response
import org.zotero.android.webdav.WebDavSessionStorage
import javax.inject.Inject

class WebDavAuthNetworkInterceptor @Inject constructor(
class WebDavBasicAuthNetworkInterceptor @Inject constructor(
private val webDavSessionStorage: WebDavSessionStorage
) : Interceptor {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,9 @@ import org.zotero.android.api.AccountApi
import org.zotero.android.api.NoAuthenticationApi
import org.zotero.android.api.NoRedirectApi
import org.zotero.android.api.SyncApi
import org.zotero.android.api.WebDavApi
import org.zotero.android.api.annotations.ForApiWithAuthentication
import org.zotero.android.api.annotations.ForApiWithNoRedirects
import org.zotero.android.api.annotations.ForBaseApi
import org.zotero.android.api.annotations.ForWebDav
import retrofit2.Retrofit
import javax.inject.Singleton

Expand Down Expand Up @@ -40,9 +38,4 @@ object ApiInterfacesModule {
return retrofit.create(NoAuthenticationApi::class.java)
}

@Provides
@Singleton
fun provideWebDavApi(@ForWebDav retrofit: Retrofit): WebDavApi {
return retrofit.create(WebDavApi::class.java)
}
}
68 changes: 0 additions & 68 deletions app/src/main/java/org/zotero/android/api/module/WebDavModule.kt

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import org.zotero.android.api.module.ApiWebSocketModule
import org.zotero.android.api.module.ApiWithAuthenticationModule
import org.zotero.android.api.module.BaseApiModule
import org.zotero.android.api.module.GeneralModule
import org.zotero.android.api.module.WebDavModule
import org.zotero.android.architecture.SdkInt
import org.zotero.android.architecture.app.AppConfig
import org.zotero.android.architecture.app.ApplicationIdProvider
Expand All @@ -40,7 +39,6 @@ import javax.inject.Singleton
ApiInterfacesModule::class,
ApiWebSocketModule::class,
ApiWithAuthenticationModule::class,
WebDavModule::class,
]
)
internal class AppModule {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ import javax.inject.Singleton
@Singleton
class BackgroundUploadProcessor @Inject constructor(
private val noAuthenticationApi: NoAuthenticationApi,
private val webDavApi: WebDavApi,
private val syncApi: SyncApi,
private val schemaController: SchemaController,
private val dbWrapperMain: DbWrapperMain,
Expand Down Expand Up @@ -120,7 +119,7 @@ class BackgroundUploadProcessor @Inject constructor(
val url = upload.remoteUrl
val newUrl = "${url}${upload.key}.zip"
val requestBody = createRequestBody(upload.fileUrl)
webDavApi.uploadAttachment(url = newUrl, body = requestBody)
webDavController.uploadAttachment(url = newUrl, body = requestBody)
}
}
}
Expand Down
93 changes: 78 additions & 15 deletions app/src/main/java/org/zotero/android/webdav/WebDavController.kt
Original file line number Diff line number Diff line change
@@ -1,14 +1,25 @@
package org.zotero.android.webdav

import android.webkit.MimeTypeMap
import com.burgstaller.okhttp.AuthenticationCacheInterceptor
import com.burgstaller.okhttp.digest.CachingAuthenticator
import com.burgstaller.okhttp.digest.Credentials
import com.burgstaller.okhttp.digest.DigestAuthenticator
import kotlinx.coroutines.suspendCancellableCoroutine
import okhttp3.ConnectionPool
import okhttp3.Dispatcher
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.OkHttpClient
import okhttp3.RequestBody
import okhttp3.RequestBody.Companion.asRequestBody
import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.ResponseBody
import okhttp3.logging.HttpLoggingInterceptor.Level
import org.zotero.android.api.ClientInfoNetworkInterceptor
import org.zotero.android.api.HttpLoggingInterceptor
import org.zotero.android.api.WebDavApi
import org.zotero.android.api.WebDavBasicAuthNetworkInterceptor
import org.zotero.android.api.network.CustomResult
import org.zotero.android.api.network.safeApiCall
import org.zotero.android.api.network.safeApiCallSync
Expand All @@ -17,14 +28,19 @@ import org.zotero.android.database.objects.RCustomLibraryType
import org.zotero.android.database.requests.StoreMtimeForAttachmentDbRequest
import org.zotero.android.files.FileStore
import org.zotero.android.helpers.Zipper
import org.zotero.android.ktx.setNetworkTimeout
import org.zotero.android.sync.LibraryIdentifier
import org.zotero.android.webdav.data.MetadataResult
import org.zotero.android.webdav.data.WebDavDeletionResult
import org.zotero.android.webdav.data.WebDavError
import org.zotero.android.webdav.data.WebDavUploadResult
import retrofit2.Response
import retrofit2.Retrofit
import timber.log.Timber
import java.io.File
import java.net.URL
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.TimeUnit
import javax.inject.Inject
import javax.inject.Singleton
import kotlin.coroutines.resume
Expand All @@ -34,8 +50,9 @@ import kotlin.coroutines.resume
class WebDavController @Inject constructor(
private val sessionStorage: WebDavSessionStorage,
private val dbWrapperMain: DbWrapperMain,
private val webDavApi: WebDavApi,
private val fileStore: FileStore,
private val webDavBasicAuthNetworkInterceptor: WebDavBasicAuthNetworkInterceptor,
private val clientInfoNetworkInterceptor: ClientInfoNetworkInterceptor,
) {

private fun update(mtime: Long, key: String): CustomResult<Unit> {
Expand Down Expand Up @@ -181,7 +198,7 @@ class WebDavController @Inject constructor(

private suspend fun checkIsDav(url: String): CustomResult<ResponseBody> {
val networkResult = safeApiCall {
webDavApi.options(url)
provideWebDavApi().options(url)
}
if (networkResult !is CustomResult.GeneralSuccess.NetworkSuccess) {
return networkResult as CustomResult.GeneralError
Expand All @@ -204,7 +221,7 @@ class WebDavController @Inject constructor(
createUrlResult as CustomResult.GeneralSuccess
val url = createUrlResult.value!!
val networkResult = safeApiCall {
webDavApi.mkcol(url)
provideWebDavApi().mkcol(url)
}

if (networkResult !is CustomResult.GeneralSuccess.NetworkSuccess) {
Expand Down Expand Up @@ -244,7 +261,7 @@ class WebDavController @Inject constructor(

val networkResult = safeApiCall {
val body: RequestBody = bodyText.toRequestBody()
webDavApi.propfind(url = url, headers = headers, body = body)
provideWebDavApi().propfind(url = url, headers = headers, body = body)
}
if (networkResult !is CustomResult.GeneralSuccess.NetworkSuccess) {
return networkResult as CustomResult.GeneralError
Expand All @@ -258,7 +275,7 @@ class WebDavController @Inject constructor(
private suspend fun checkWhetherReturns404ForMissingFile(url: String): CustomResult<Unit> {
val appendedUrl = "${url}nonexistent.prop"
val networkResult = safeApiCall {
webDavApi.get(url = appendedUrl)
provideWebDavApi().get(url = appendedUrl)
}
if (networkResult is CustomResult.GeneralError.NetworkError) {
if (networkResult.httpCode == 404) {
Expand Down Expand Up @@ -295,7 +312,7 @@ class WebDavController @Inject constructor(

private suspend fun webDavDeleteRequest(url: String): CustomResult<ResponseBody> {
val networkResult = safeApiCall {
webDavApi.delete(url = url)
provideWebDavApi().delete(url = url)
}
if (networkResult is CustomResult.GeneralError.NetworkError) {
return networkResult
Expand All @@ -309,7 +326,7 @@ class WebDavController @Inject constructor(

private suspend fun webDavDownloadRequest(url: String): CustomResult<ResponseBody> {
val networkResult = safeApiCall {
webDavApi.get(url = url)
provideWebDavApi().get(url = url)
}
if (networkResult is CustomResult.GeneralError.NetworkError) {
if (networkResult.httpCode == 404) {
Expand All @@ -329,7 +346,7 @@ class WebDavController @Inject constructor(

val networkResult = safeApiCall {
val body: RequestBody = RequestBody.create("text/plain".toMediaType(), bodyText);
webDavApi.put(url = url, body = body)
provideWebDavApi().put(url = url, body = body)
}

if (networkResult is CustomResult.GeneralError.NetworkError) {
Expand Down Expand Up @@ -373,7 +390,7 @@ class WebDavController @Inject constructor(
checkServerIfNeededResult as CustomResult.GeneralSuccess
val newUrl = "${checkServerIfNeededResult.value}$key.zip"
return safeApiCall {
webDavApi.downloadFile(newUrl)
provideWebDavApi().downloadFile(newUrl)
}
}

Expand Down Expand Up @@ -428,7 +445,7 @@ class WebDavController @Inject constructor(
private suspend fun metadata(key: String, url: String): CustomResult<Pair<Long, String>?> {
val newUrl = "${url}${key}.prop"
val networkResult = safeApiCall {
webDavApi.get(url = newUrl)
provideWebDavApi().get(url = newUrl)
}
if (networkResult is CustomResult.GeneralError.NetworkError) {
if (networkResult.httpCode == 404) {
Expand Down Expand Up @@ -463,7 +480,7 @@ class WebDavController @Inject constructor(
val newUrl = "${url}${key}.prop"

val networkResult = safeApiCall {
webDavApi.delete(url = newUrl)
provideWebDavApi().delete(url = newUrl)
}
if (networkResult is CustomResult.GeneralError.NetworkError) {
return networkResult
Expand Down Expand Up @@ -603,7 +620,7 @@ class WebDavController @Inject constructor(
val newUrl = "${url}${key}.prop"

val networkResult = safeApiCall {
webDavApi.uploadProp(url = newUrl, body = data)
provideWebDavApi().uploadProp(url = newUrl, body = data)
}

if (networkResult is CustomResult.GeneralError.NetworkError) {
Expand All @@ -620,7 +637,7 @@ class WebDavController @Inject constructor(
val requestBody = createRequestBody(file)

val networkResult = safeApiCall {
webDavApi.uploadAttachment(url = newUrl, body = requestBody)
provideWebDavApi().uploadAttachment(url = newUrl, body = requestBody)
}

if (networkResult is CustomResult.GeneralError.NetworkError) {
Expand Down Expand Up @@ -708,7 +725,7 @@ class WebDavController @Inject constructor(

val zipUrl = "${url}${key}.zip"
val deleteZipResult = safeApiCallSync {
webDavApi.deleteSync(url = zipUrl)
provideWebDavApi().deleteSync(url = zipUrl)
}
if (deleteZipResult is CustomResult.GeneralError) {
processResult(key, deleteZipResult)
Expand All @@ -729,7 +746,7 @@ class WebDavController @Inject constructor(
) {
val propUrl = "${url}${key}.prop"
val deletePropResult = safeApiCallSync {
webDavApi.deleteSync(url = propUrl)
provideWebDavApi().deleteSync(url = propUrl)
}
if (deletePropResult is CustomResult.GeneralError) {
processResult(key, deletePropResult)
Expand All @@ -743,5 +760,51 @@ class WebDavController @Inject constructor(
processResult(key, deletePropResult)
}

suspend fun uploadAttachment(url: String, body: RequestBody): Response<Unit> {
return provideWebDavApi().uploadAttachment(url, body)
}

private fun provideWebDavOkHttpClient(
): OkHttpClient {
val connectionPool = ConnectionPool(
maxIdleConnections = 10,
keepAliveDuration = 5,
timeUnit = TimeUnit.MINUTES
)
val dispatcher = Dispatcher()
dispatcher.maxRequests = 30
dispatcher.maxRequestsPerHost = 30

val authCache: Map<String, CachingAuthenticator> =
ConcurrentHashMap<String, CachingAuthenticator>()
val username = sessionStorage.username
val password = sessionStorage.password

return OkHttpClient.Builder()
.dispatcher(dispatcher)
.connectionPool(connectionPool)
.setNetworkTimeout(15L)
.addInterceptor(webDavBasicAuthNetworkInterceptor)
.authenticator(DigestAuthenticator(Credentials(username, password)))
.addInterceptor(AuthenticationCacheInterceptor(authCache))
.addInterceptor(clientInfoNetworkInterceptor)
.addInterceptor(HttpLoggingInterceptor.createInterceptor(Level.BODY))
.build()
}

private fun provideWebDavRetrofit(
): Retrofit {
val okHttpClient = provideWebDavOkHttpClient()
val retrofitBuilder = Retrofit.Builder()
return retrofitBuilder
.baseUrl("https://dummyurl.com") //no-op as all URLs for webdav are absolute
.client(okHttpClient)
.build()
}

private fun provideWebDavApi(): WebDavApi {
val retrofit = provideWebDavRetrofit()
return retrofit.create(WebDavApi::class.java)
}

}
2 changes: 1 addition & 1 deletion buildSrc/src/main/kotlin/BuildConfig.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ object BuildConfig {
const val compileSdkVersion = 34
const val targetSdk = 34

val versionCode = 92 // Must be updated on every build
val versionCode = 94 // Must be updated on every build
val version = Version(
major = 1,
minor = 0,
Expand Down
1 change: 1 addition & 0 deletions buildSrc/src/main/kotlin/Libs.kt
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ object Libs {
const val converterGson = "com.squareup.retrofit2:converter-gson:$version"
const val converterScalars = "com.squareup.retrofit2:converter-scalars:$version"

const val digest = "io.github.rburgst:okhttp-digest:3.1.0"
const val kotlinSerialization =
"com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:0.8.0"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ private fun configure(project: Project) {
add("implementation", Libs.Retrofit.core)
add("implementation", Libs.Retrofit.converterGson)
add("implementation", Libs.Retrofit.converterScalars)
add("implementation", Libs.Retrofit.digest)

add("implementation", Libs.OkHttp.core)
add("implementation", Libs.OkHttp.loggingInterceptor)
Expand Down

0 comments on commit 561a4f5

Please sign in to comment.