All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.joern.console.scan.package.scala Maven / Gradle / Ivy

There is a newer version: 4.0.131
Show newest version
package io.joern.console

import io.joern.console.Query
import io.shiftleft.codepropertygraph.generated.Cpg
import io.shiftleft.codepropertygraph.generated.NodeTypes
import io.shiftleft.codepropertygraph.generated.nodes.*
import io.shiftleft.semanticcpg.language.*
import org.slf4j.{Logger, LoggerFactory}

package object scan {

  private val logger: Logger = LoggerFactory.getLogger(this.getClass)

  implicit class QueryWrapper(q: Query) {

    /** Obtain list of findings by running query on CPG
      */
    def apply(cpg: Cpg): List[NewFinding] = {
      try {
        q.traversal(cpg)
          .map(evidence =>
            finding(
              evidence = evidence,
              name = q.name,
              author = q.author,
              title = q.title,
              description = q.description,
              score = q.score
            )
          )
          .l
      } catch {
        case ex: Throwable =>
          logger.warn("Error executing query", ex)
          List()
      }

    }
  }

  private object FindingKeys {
    val name        = "name"
    val author      = "author"
    val title       = "title"
    val description = "description"
    val score       = "score"
  }

  implicit class ScannerFindingStep(val traversal: Iterator[Finding]) extends AnyRef {

    def name: Iterator[String] = traversal.map(_.name)

    def author: Iterator[String] = traversal.map(_.author)

    def title: Iterator[String] = traversal.map(_.title)

    def description: Iterator[String] = traversal.map(_.description)

    def score: Iterator[Double] = traversal.map(_.score)

  }

  implicit class ScannerFindingExtension(val node: Finding) extends AnyRef {

    def name: String = getValue(FindingKeys.name)

    def author: String = getValue(FindingKeys.author)

    def title: String = getValue(FindingKeys.title)

    def description: String = getValue(FindingKeys.description)

    def score: Double = getValue(FindingKeys.score).toDouble

    protected def getValue(key: String, default: String = ""): String =
      node.keyValuePairs.find(_.key == key).map(_.value).getOrElse(default)

  }

  private def finding(
    evidence: StoredNode,
    name: String,
    author: String,
    title: String,
    description: String,
    score: Double
  ): NewFinding = {
    NewFinding()
      .evidence(List(evidence))
      .keyValuePairs(
        List(
          NewKeyValuePair().key(FindingKeys.name).value(name),
          NewKeyValuePair().key(FindingKeys.author).value(author),
          NewKeyValuePair().key(FindingKeys.title).value(title),
          NewKeyValuePair().key(FindingKeys.description).value(description),
          NewKeyValuePair().key(FindingKeys.score).value(score.toString)
        )
      )
  }

  /** Print human readable list of findings to standard out.
    */
  def outputFindings(cpg: Cpg)(implicit finder: NodeExtensionFinder): Unit = {
    cpg.finding.sortBy(_.score.toInt).foreach { finding =>
      val evidence = finding.evidence.headOption
        .map { e =>
          s"${e.location.filename}:${e.location.lineNumber.getOrElse(0)}:${e.location.methodFullName}"
        }
        .getOrElse("")
      println(s"Result: ${finding.score} : ${finding.title}: $evidence")
    }
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy