// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.credentialStore.keePass import com.intellij.credentialStore.CredentialAttributes import com.intellij.credentialStore.Credentials import com.intellij.credentialStore.EncryptionSpec import com.intellij.credentialStore.createSecureRandom import com.intellij.openapi.util.ThreadLocalCachedValue import com.intellij.testFramework.assertions.Assertions.assertThat import com.intellij.testFramework.rules.InMemoryFsRule import org.junit.Rule import java.awt.Component import java.nio.file.Path import java.security.SecureRandom internal val SECURE_RANDOM_CACHE = object : ThreadLocalCachedValue() { public override fun create() = createSecureRandom() } internal open class BaseKeePassFileManagerTest { companion object { val testCredentialAttributes = CredentialAttributes("foo", "u") } @JvmField @Rule val fsRule = InMemoryFsRule() protected fun createTestStoreWithCustomMasterKey(baseDir: Path = fsRule.fs.getPath("/")): KeePassCredentialStore { val store = createStore(baseDir) store.set(testCredentialAttributes, Credentials("u", "p")) store.setMasterKey("foo", SECURE_RANDOM_CACHE.value) return store } protected fun createStore() = createStore(fsRule.fs.getPath("/")) protected fun checkStoreAfterSuccessfulImport(store: KeePassCredentialStore) { store.reload() assertThat(store.dbFile).exists() assertThat(store.mainKeyFile).exists() assertThat(store.get(testCredentialAttributes)!!.getPasswordAsString()).isEqualTo("p") } } internal class TestKeePassFileManager( file: Path, masterKeyFile: Path, private val masterPasswordRequestAnswer: String? = null, private val oldMasterPasswordRequestAnswer: String? = null, masterKeyEncryptionSpec: EncryptionSpec = defaultEncryptionSpec ) : KeePassFileManager(file, masterKeyFile, masterKeyEncryptionSpec, lazyOf(SECURE_RANDOM_CACHE.value)) { constructor(store: KeePassCredentialStore, masterPasswordRequestAnswer: String? = null, oldMasterPasswordRequestAnswer: String? = null, masterKeyEncryptionSpec: EncryptionSpec = defaultEncryptionSpec) : this(store.dbFile, store.mainKeyFile, masterPasswordRequestAnswer, oldMasterPasswordRequestAnswer, masterKeyEncryptionSpec) var isUnsatisfiedMasterPasswordRequest = false override fun requestMainPassword(title: String, topNote: String?, contextComponent: Component?, ok: (value: ByteArray) -> String?): Boolean { if (masterPasswordRequestAnswer == null) { isUnsatisfiedMasterPasswordRequest = true return false } else { assertThat(ok(masterPasswordRequestAnswer.toByteArray())).isNull() return true } } override fun requestCurrentAndNewKeys(contextComponent: Component?): Boolean { doSetNewMainPassword(oldMasterPasswordRequestAnswer!!.toCharArray(), masterPasswordRequestAnswer!!.toCharArray()) return true } } internal fun KeePassCredentialStore.setMasterKey(value: String, secureRandom: SecureRandom) { setMainPassword(MainKey(value.toByteArray(), isAutoGenerated = false, encryptionSpec = defaultEncryptionSpec), secureRandom) }