As Scala Library
Describes how to use recheck
as a Scala library.
Install
To install the Scala library of recheck
, you should append the following line into your 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.
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).
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.concurrent
or 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()
There is the timeout
parameter to specify timeout seconds.
Please use this instead of the manual way.
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()