Skip to content

Commit

Permalink
Added LFS credentials caching
Browse files Browse the repository at this point in the history
  • Loading branch information
JetpackDuba committed Feb 11, 2025
1 parent 12c4b5a commit c6ce532
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,19 @@ class CredentialsCacheRepository @Inject constructor() {
// having a random key to encrypt the password may help in case of a memory dump attack
private val encryptionKey = getRandomKey()

fun getCachedHttpCredentials(url: String): CredentialsType.HttpCredentials? {
fun getCachedHttpCredentials(url: String, isLfs: Boolean): CredentialsType.HttpCredentials? {
val credentials = credentialsCached.filterIsInstance<CredentialsType.HttpCredentials>().firstOrNull {
it.url == url
it.url == url && it.isLfs == isLfs
}

return credentials?.copy(password = credentials.password.cipherDecrypt())
}

suspend fun cacheHttpCredentials(credentials: CredentialsType.HttpCredentials) {
cacheHttpCredentials(credentials.url, credentials.userName, credentials.password)
cacheHttpCredentials(credentials.url, credentials.userName, credentials.password, credentials.isLfs)
}

suspend fun cacheHttpCredentials(url: String, userName: String, password: String) {
suspend fun cacheHttpCredentials(url: String, userName: String, password: String, isLfs: Boolean) {
val passwordEncrypted = password.cipherEncrypt()

credentialsLock.lockUse {
Expand All @@ -41,7 +41,7 @@ class CredentialsCacheRepository @Inject constructor() {
}

if (!previouslyCached) {
val credentials = CredentialsType.HttpCredentials(url, userName, passwordEncrypted)
val credentials = CredentialsType.HttpCredentials(url, userName, passwordEncrypted, isLfs)
credentialsCached.add(credentials)
}
}
Expand Down Expand Up @@ -101,5 +101,6 @@ sealed interface CredentialsType {
val url: String,
val userName: String,
val password: String,
val isLfs: Boolean,
) : CredentialsType
}
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,10 @@ class HttpCredentialsProvider @AssistedInject constructor(
val externalCredentialsHelper = getExternalCredentialsHelper(uri, git)

if (externalCredentialsHelper == null) {
val cachedCredentials = credentialsCacheRepository.getCachedHttpCredentials(uri.toString())
val cachedCredentials = credentialsCacheRepository.getCachedHttpCredentials(
url = uri.toString(),
isLfs = false,
)

if (cachedCredentials == null) {
val credentials = askForCredentials()
Expand All @@ -92,6 +95,7 @@ class HttpCredentialsProvider @AssistedInject constructor(
url = uri.toString(),
userName = credentials.user,
password = credentials.password,
isLfs = false,
)
}

Expand Down
11 changes: 10 additions & 1 deletion src/main/kotlin/com/jetpackduba/gitnuro/lfs/GLfsFactory.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.jetpackduba.gitnuro.lfs

import com.jetpackduba.gitnuro.Result
import com.jetpackduba.gitnuro.credentials.CredentialsAccepted
import com.jetpackduba.gitnuro.credentials.CredentialsCacheRepository
import com.jetpackduba.gitnuro.credentials.CredentialsRequest
import com.jetpackduba.gitnuro.credentials.CredentialsStateManager
import com.jetpackduba.gitnuro.logging.printLog
Expand Down Expand Up @@ -41,10 +42,18 @@ private const val TAG = "GLfsFactory"
class GLfsFactory @Inject constructor(
private val lfsRepository: LfsRepository,
private val credentialsStateManager: CredentialsStateManager,
private val credentialsCacheRepository: CredentialsCacheRepository,
) : LfsFactory() {
init {
FilterCommandRegistry.register("jgit://builtin/lfs/smudge") { repository, input, out ->
LfsSmudgeFilter(lfsRepository, credentialsStateManager, input, out, repository)
LfsSmudgeFilter(
lfsRepository = lfsRepository,
credentialsStateManager = credentialsStateManager,
credentialsCacheRepository = credentialsCacheRepository,
input = input,
output = out,
repository = repository
)
}
FilterCommandRegistry.register("jgit://builtin/lfs/clean") { db, `in`, out ->
LfsCleanFilter(db, `in`, out)
Expand Down
33 changes: 32 additions & 1 deletion src/main/kotlin/com/jetpackduba/gitnuro/lfs/LfsSmudgeFilter.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.jetpackduba.gitnuro.lfs

import com.jetpackduba.gitnuro.Result
import com.jetpackduba.gitnuro.credentials.CredentialsAccepted
import com.jetpackduba.gitnuro.credentials.CredentialsCacheRepository
import com.jetpackduba.gitnuro.credentials.CredentialsRequest
import com.jetpackduba.gitnuro.credentials.CredentialsStateManager
import com.jetpackduba.gitnuro.logging.printLog
Expand All @@ -16,6 +17,7 @@ import org.eclipse.jgit.lfs.LfsPointer
import org.eclipse.jgit.lfs.lib.AnyLongObjectId
import org.eclipse.jgit.lib.Repository
import java.io.*
import java.net.URI
import java.nio.file.Files
import java.util.concurrent.CancellationException

Expand All @@ -24,6 +26,7 @@ private const val MAX_COPY_BYTES = 1024 * 1024 * 256
class LfsSmudgeFilter(
private val lfsRepository: LfsRepository,
private val credentialsStateManager: CredentialsStateManager,
private val credentialsCacheRepository: CredentialsCacheRepository,
input: InputStream,
output: OutputStream,
repository: Repository,
Expand Down Expand Up @@ -57,6 +60,7 @@ class LfsSmudgeFilter(
res: LfsPointer,
) = runBlocking {
val lfsServerUrl = lfsRepository.getLfsRepositoryUrl(repository)

val hash = res.oid.name()
val size = res.size

Expand All @@ -67,17 +71,44 @@ class LfsSmudgeFilter(
)

var credentials: CredentialsAccepted.LfsCredentialsAccepted? = null
var cachedCredentialsAlreadyRequested = false

val lfsObjects = getLfsObjects(lfsServerUrl, lfsPrepareUploadObjectBatch) {
if (!cachedCredentialsAlreadyRequested) {
val cachedCredentials = credentialsCacheRepository.getCachedHttpCredentials(lfsServerUrl, true)

if (cachedCredentials != null) {
val newCredentials = CredentialsAccepted.LfsCredentialsAccepted(
user = cachedCredentials.userName,
password = cachedCredentials.password,
)

credentials = newCredentials

cachedCredentialsAlreadyRequested = true

return@getLfsObjects newCredentials
}
}

val newCredentials = requestLfsCredentials()
credentials = newCredentials

newCredentials
return@getLfsObjects newCredentials
}

when (lfsObjects) {
is Result.Err -> throw Exception("LFS Error ${lfsObjects.error}")
is Result.Ok -> {
credentials?.let { safeCredentials ->
credentialsCacheRepository.cacheHttpCredentials(
lfsServerUrl,
safeCredentials.user,
safeCredentials.password,
isLfs = true,
)
}

val lfs = Lfs(repository)

printLog("LFS", "Requesting credentials for objects upload")
Expand Down

0 comments on commit c6ce532

Please sign in to comment.