Skip to content

Commit 6cbc872

Browse files
Godinleveretka
andauthored
SONARKT-460 Migrate ServerCertificateCheck to kotlin-analysis-api
Co-authored-by: Marharyta Nedzelska <[email protected]> Co-authored-by: Evgeny Mandrikov <[email protected]>
1 parent 81d892e commit 6cbc872

File tree

1 file changed

+21
-24
lines changed

1 file changed

+21
-24
lines changed

sonar-kotlin-checks/src/main/java/org/sonarsource/kotlin/checks/ServerCertificateCheck.kt

Lines changed: 21 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -17,21 +17,17 @@
1717
package org.sonarsource.kotlin.checks
1818

1919
import com.intellij.psi.PsiElement
20-
import org.jetbrains.kotlin.js.descriptorUtils.getKotlinTypeFqName
20+
import org.jetbrains.kotlin.name.ClassId
2121
import org.jetbrains.kotlin.psi.KtCallExpression
2222
import org.jetbrains.kotlin.psi.KtCatchClause
2323
import org.jetbrains.kotlin.psi.KtNamedFunction
2424
import org.jetbrains.kotlin.psi.KtThrowExpression
2525
import org.jetbrains.kotlin.psi.KtVisitorVoid
26-
import org.jetbrains.kotlin.resolve.BindingContext
2726
import org.sonar.check.Rule
2827
import org.sonarsource.kotlin.api.checks.AbstractCheck
2928
import org.sonarsource.kotlin.api.checks.FunMatcher
30-
import org.sonarsource.kotlin.api.checks.determineType
3129
import org.sonarsource.kotlin.api.frontend.KotlinFileContext
32-
33-
34-
private const val CERTIFICATE_EXCEPTION = "java.security.cert.CertificateException"
30+
import org.sonarsource.kotlin.api.visiting.withKaSession
3531

3632
private val funMatchers = listOf(
3733
FunMatcher {
@@ -43,34 +39,31 @@ private val funMatchers = listOf(
4339
withNames("checkClientTrusted", "checkServerTrusted")
4440
})
4541

46-
47-
@org.sonarsource.kotlin.api.frontend.K1only
4842
@Rule(key = "S4830")
4943
class ServerCertificateCheck : AbstractCheck() {
50-
override fun visitNamedFunction(function: KtNamedFunction, kotlinFileContext: KotlinFileContext) {
51-
val (_, _, bindingContext) = kotlinFileContext
5244

53-
if (function.belongsToTrustManagerClass(bindingContext)
54-
&& !function.callsCheckTrusted(bindingContext)
55-
&& !function.throwsCertificateExceptionWithoutCatching(bindingContext)
45+
override fun visitNamedFunction(function: KtNamedFunction, kotlinFileContext: KotlinFileContext) {
46+
if (function.belongsToTrustManagerClass()
47+
&& !function.callsCheckTrusted()
48+
&& !function.throwsCertificateExceptionWithoutCatching()
5649
) {
5750
kotlinFileContext.reportIssue(function.nameIdentifier ?: function,
5851
"Enable server certificate validation on this SSL/TLS connection.")
5952
}
6053
}
6154

62-
private fun KtNamedFunction.belongsToTrustManagerClass(bindingContext: BindingContext): Boolean =
63-
funMatchers.any { it.matches(this, bindingContext) }
55+
private fun KtNamedFunction.belongsToTrustManagerClass(): Boolean =
56+
funMatchers.any { it.matches(this) }
6457

6558
/*
6659
* Returns true if a function contains a call to "checkClientTrusted" or "checkServerTrusted".
6760
*/
68-
private fun KtNamedFunction.callsCheckTrusted(bindingContext: BindingContext): Boolean {
61+
private fun KtNamedFunction.callsCheckTrusted(): Boolean {
6962
val visitor = object : KtVisitorVoid() {
7063
private var foundCheckTrustedCall: Boolean = false
7164

7265
override fun visitCallExpression(expression: KtCallExpression) {
73-
foundCheckTrustedCall = foundCheckTrustedCall || funMatchers.any { it.matches(expression, bindingContext) }
66+
foundCheckTrustedCall = foundCheckTrustedCall || funMatchers.any { it.matches(expression) }
7467
}
7568

7669
fun callsCheckTrusted(): Boolean = foundCheckTrustedCall
@@ -82,24 +75,28 @@ class ServerCertificateCheck : AbstractCheck() {
8275
/*
8376
* Returns true only when the function throws a CertificateException without a catch against it.
8477
*/
85-
private fun KtNamedFunction.throwsCertificateExceptionWithoutCatching(bindingContext: BindingContext): Boolean {
86-
val visitor = ThrowCatchVisitor(bindingContext)
78+
private fun KtNamedFunction.throwsCertificateExceptionWithoutCatching(): Boolean {
79+
val visitor = ThrowCatchVisitor()
8780
this.acceptRecursively(visitor)
8881
return visitor.throwsCertificateExceptionWithoutCatching()
8982
}
9083

91-
private class ThrowCatchVisitor(private val bindingContext: BindingContext) : KtVisitorVoid() {
84+
private class ThrowCatchVisitor : KtVisitorVoid() {
85+
private val certificateExceptionClassId = ClassId.fromString("java/security/cert/CertificateException")
86+
9287
private var throwFound: Boolean = false
9388
private var catchFound: Boolean = false
9489

95-
override fun visitThrowExpression(expression: KtThrowExpression) {
90+
override fun visitThrowExpression(expression: KtThrowExpression) = withKaSession {
9691
throwFound =
97-
throwFound || CERTIFICATE_EXCEPTION == expression.thrownExpression.determineType(bindingContext)?.getKotlinTypeFqName(false)
92+
throwFound ||
93+
expression.thrownExpression?.expressionType?.isClassType(certificateExceptionClassId) == true
9894
}
9995

100-
override fun visitCatchSection(catchClause: KtCatchClause) {
96+
override fun visitCatchSection(catchClause: KtCatchClause) = withKaSession {
10197
catchFound =
102-
catchFound || CERTIFICATE_EXCEPTION == catchClause.catchParameter.determineType(bindingContext)?.getKotlinTypeFqName(false)
98+
catchFound ||
99+
catchClause.catchParameter?.symbol?.returnType?.isClassType(certificateExceptionClassId) == true
103100
}
104101

105102
fun throwsCertificateExceptionWithoutCatching(): Boolean {

0 commit comments

Comments
 (0)