1717package org.sonarsource.kotlin.checks
1818
1919import com.intellij.psi.PsiElement
20- import org.jetbrains.kotlin.js.descriptorUtils.getKotlinTypeFqName
20+ import org.jetbrains.kotlin.name.ClassId
2121import org.jetbrains.kotlin.psi.KtCallExpression
2222import org.jetbrains.kotlin.psi.KtCatchClause
2323import org.jetbrains.kotlin.psi.KtNamedFunction
2424import org.jetbrains.kotlin.psi.KtThrowExpression
2525import org.jetbrains.kotlin.psi.KtVisitorVoid
26- import org.jetbrains.kotlin.resolve.BindingContext
2726import org.sonar.check.Rule
2827import org.sonarsource.kotlin.api.checks.AbstractCheck
2928import org.sonarsource.kotlin.api.checks.FunMatcher
30- import org.sonarsource.kotlin.api.checks.determineType
3129import 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
3632private 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" )
4943class 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