From 5b4ad4dec61a984e978f0b43fbddcbf04b410c68 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Thu, 5 Dec 2024 01:51:15 +0100 Subject: [PATCH] Migrate ServerCertificateCheck to kotlin-analysis-api --- .../kotlin/checks/ServerCertificateCheck.kt | 39 +++++++++---------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/ServerCertificateCheck.kt b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/ServerCertificateCheck.kt index 36d6c0b72..c13746de5 100644 --- a/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/ServerCertificateCheck.kt +++ b/sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/ServerCertificateCheck.kt @@ -17,18 +17,18 @@ package org.sonarsource.kotlin.checks import com.intellij.psi.PsiElement -import org.jetbrains.kotlin.js.descriptorUtils.getKotlinTypeFqName +import org.jetbrains.kotlin.analysis.api.types.symbol import org.jetbrains.kotlin.psi.KtCallExpression import org.jetbrains.kotlin.psi.KtCatchClause import org.jetbrains.kotlin.psi.KtNamedFunction import org.jetbrains.kotlin.psi.KtThrowExpression import org.jetbrains.kotlin.psi.KtVisitorVoid -import org.jetbrains.kotlin.resolve.BindingContext import org.sonar.check.Rule import org.sonarsource.kotlin.api.checks.AbstractCheck import org.sonarsource.kotlin.api.checks.FunMatcher import org.sonarsource.kotlin.api.checks.determineType import org.sonarsource.kotlin.api.frontend.KotlinFileContext +import org.sonarsource.kotlin.api.visiting.withKaSession private const val CERTIFICATE_EXCEPTION = "java.security.cert.CertificateException" @@ -43,34 +43,31 @@ private val funMatchers = listOf( withNames("checkClientTrusted", "checkServerTrusted") }) - -@org.sonarsource.kotlin.api.frontend.K1only @Rule(key = "S4830") class ServerCertificateCheck : AbstractCheck() { - override fun visitNamedFunction(function: KtNamedFunction, kotlinFileContext: KotlinFileContext) { - val (_, _, bindingContext) = kotlinFileContext - if (function.belongsToTrustManagerClass(bindingContext) - && !function.callsCheckTrusted(bindingContext) - && !function.throwsCertificateExceptionWithoutCatching(bindingContext) + override fun visitNamedFunction(function: KtNamedFunction, kotlinFileContext: KotlinFileContext) { + if (function.belongsToTrustManagerClass() + && !function.callsCheckTrusted() + && !function.throwsCertificateExceptionWithoutCatching() ) { kotlinFileContext.reportIssue(function.nameIdentifier ?: function, "Enable server certificate validation on this SSL/TLS connection.") } } - private fun KtNamedFunction.belongsToTrustManagerClass(bindingContext: BindingContext): Boolean = - funMatchers.any { it.matches(this, bindingContext) } + private fun KtNamedFunction.belongsToTrustManagerClass(): Boolean = + funMatchers.any { it.matches(this) } /* * Returns true if a function contains a call to "checkClientTrusted" or "checkServerTrusted". */ - private fun KtNamedFunction.callsCheckTrusted(bindingContext: BindingContext): Boolean { + private fun KtNamedFunction.callsCheckTrusted(): Boolean { val visitor = object : KtVisitorVoid() { private var foundCheckTrustedCall: Boolean = false override fun visitCallExpression(expression: KtCallExpression) { - foundCheckTrustedCall = foundCheckTrustedCall || funMatchers.any { it.matches(expression, bindingContext) } + foundCheckTrustedCall = foundCheckTrustedCall || funMatchers.any { it.matches(expression) } } fun callsCheckTrusted(): Boolean = foundCheckTrustedCall @@ -82,24 +79,26 @@ class ServerCertificateCheck : AbstractCheck() { /* * Returns true only when the function throws a CertificateException without a catch against it. */ - private fun KtNamedFunction.throwsCertificateExceptionWithoutCatching(bindingContext: BindingContext): Boolean { - val visitor = ThrowCatchVisitor(bindingContext) + private fun KtNamedFunction.throwsCertificateExceptionWithoutCatching(): Boolean { + val visitor = ThrowCatchVisitor() this.acceptRecursively(visitor) return visitor.throwsCertificateExceptionWithoutCatching() } - private class ThrowCatchVisitor(private val bindingContext: BindingContext) : KtVisitorVoid() { + private class ThrowCatchVisitor : KtVisitorVoid() { private var throwFound: Boolean = false private var catchFound: Boolean = false - override fun visitThrowExpression(expression: KtThrowExpression) { + override fun visitThrowExpression(expression: KtThrowExpression) = withKaSession { throwFound = - throwFound || CERTIFICATE_EXCEPTION == expression.thrownExpression.determineType(bindingContext)?.getKotlinTypeFqName(false) + throwFound || CERTIFICATE_EXCEPTION == + expression.thrownExpression?.expressionType?.symbol?.classId?.asFqNameString() } - override fun visitCatchSection(catchClause: KtCatchClause) { + override fun visitCatchSection(catchClause: KtCatchClause) = withKaSession { catchFound = - catchFound || CERTIFICATE_EXCEPTION == catchClause.catchParameter.determineType(bindingContext)?.getKotlinTypeFqName(false) + catchFound || CERTIFICATE_EXCEPTION == + catchClause.catchParameter?.determineType()?.symbol?.classId?.asFqNameString() } fun throwsCertificateExceptionWithoutCatching(): Boolean {