Skip to main content

As Scala Library

Describes how to use recheck as a Scala library.

Install

Maven Central

To install the Scala library of recheck, you should append the following line into your build.sbt.

build.sbt
libraryDependencies += "codes.quine.labs" %% "recheck-core" % "4.5.0-beta.6"

Usage

ReDoS.check is the only entry point for checking the vulnerability of regular expression.

import codes.quine.labs.recheck.ReDoS

ReDoS.check("^(a|a)*$", "")

The first argument of ReDoS.check is the source which is corresponding to RegExp.prototype.source. And, the second argument is the flags which is corresponding to RegExp.prototype.flags too. The third argument is the params to specify parameters for the checker behavior, and the fourth is the token to cancel the checking in the middle.

info

See this page for detailed information on Parameters value.

The result of ReDoS.check is called Diagnostics. Diagnostics is a sealed class, and it has three child classes.

  • Diagnostics.Safe means the given regular expression seems safe at least in this checking.
  • Diagnostics.Vulnerable means vulnerability in the given regular expression is found.
  • Diagnostics.Unknown means something wrong happened in checking (timeout, cancel, or error).
info

See this page for detailed information on Diagnostics value.

Cancel

The fourth argument of ReDoS.check is used to cancel the checking in the middle. This type is CancellationToken which is created by CancellationTokenSource. Noting that ReDoS.check blocks the process, you should use this with concurrent libraries like scala.concurrentor cats-effect.

The following example is usage with cats-effect.

import scala.concurrent.duration._

import cats.effect._
import cats.effect.unsafe.implicits.global

import codes.quine.labs.recheck.ReDoS
import codes.quine.labs.recheck.common.CancellationTokenSource
import codes.quine.labs.recheck.common.Parameters
import codes.quine.labs.recheck.diagnostics.Diagnostics

val cancellation = new CancellationTokenSource

val io = for {
fiber <- IO(ReDoS.check("^a+a+$", "", Parameters(), Some(cancellation.token))).start
_ <- (IO.sleep(100.millisecond) *> IO(cancellation.cancel())).start
diagnostics <- fiber.joinWithNever
_ <- IO.println(diagnostics)
} yield ()

io.unsafeRunSync()
caution

There is the timeout parameter to specify timeout seconds. Please use this instead of the manual way.

note

The above example does not work with cats-effect better actually, because fiber has cancel method and it does not work with this method.

To fix this problem, we can use IO.async. The following is the complete example. However, by cats-effect restriction, it will lose a result diagnostics when a fiber is cancelled.

import scala.concurrent.duration._

import cats.effect._
import cats.effect.unsafe.implicits.global

import codes.quine.labs.recheck.ReDoS
import codes.quine.labs.recheck.common.CancellationTokenSource
import codes.quine.labs.recheck.common.Parameters
import codes.quine.labs.recheck.diagnostics.Diagnostics

def cancelableCheck(source: String, flags: String, params: Parameters): IO[Diagnostics] =
IO.executionContext.flatMap { ec =>
IO.async { cb =>
IO {
val cancellation = new CancellationTokenSource
ec.execute(() => {
val diagnostics = ReDoS.check(source, flags, params, Some(cancellation.token))
cb(Right(diagnostics))
})
Some(IO(cancellation.cancel()))
}
}
}

val io = for {
fiber <- cancelableCheck("^a+a+$", "", Parameters()).start
_ <- (IO.sleep(100.millisecond) *> fiber.cancel).start
diagnostics <- fiber.join
_ <- IO.println(diagnostics)
} yield ()

io.unsafeRunSync()