diff --git a/app/Filters.scala b/app/Filters.scala new file mode 100644 index 0000000..3603224 --- /dev/null +++ b/app/Filters.scala @@ -0,0 +1,6 @@ +import javax.inject.Inject +import play.api.http.DefaultHttpFilters +import play.filters.cors.CORSFilter + +class Filters @Inject() (corsFilter: CORSFilter) + extends DefaultHttpFilters(corsFilter) diff --git a/app/actions/CORSAction.scala b/app/actions/CORSAction.scala new file mode 100644 index 0000000..05fc344 --- /dev/null +++ b/app/actions/CORSAction.scala @@ -0,0 +1,34 @@ +package actions + +import javax.inject.Inject +import play.api.mvc._ +import play.api.http.HttpErrorHandler +import play.filters.cors.{CORSActionBuilder, CORSConfig} +import scala.concurrent.{ExecutionContext, Future} +import org.apache.pekko.stream.Materializer + +class CORSAction @Inject() ( + parser: BodyParsers.Default, + corsConfig: CORSConfig, + errorHandler: HttpErrorHandler, + val controllerComponents: ControllerComponents +)(implicit ec: ExecutionContext, mat: Materializer) + extends CORSActionBuilder + with BaseController { + + override protected def corsConfig: CORSConfig = corsConfig + override protected def errorHandler: HttpErrorHandler = errorHandler + override protected def mat: Materializer = mat + + override def parser: BodyParser[AnyContent] = parser + override def executionContext: ExecutionContext = ec + + override def invokeBlock[A](request: Request[A], block: Request[A] => Future[Result]): Future[Result] = { + block(request).map(_.withHeaders( + "Access-Control-Allow-Origin" -> "*", + "Access-Control-Allow-Methods" -> "GET, POST, OPTIONS", + "Access-Control-Allow-Headers" -> "Origin, Content-Type, Accept, Authorization", + "Access-Control-Allow-Credentials" -> "true" + )) + } +} diff --git a/app/controllers/HomeController.scala b/app/controllers/HomeController.scala index 58c5a34..aaae472 100644 --- a/app/controllers/HomeController.scala +++ b/app/controllers/HomeController.scala @@ -1,24 +1,17 @@ package controllers import play.api.mvc._ +import actions.CORSAction import javax.inject._ -/** - * This controller creates an `Action` to handle HTTP requests to the - * application's home page. - */ @Singleton -class HomeController @Inject()(val controllerComponents: ControllerComponents) extends BaseController { +class HomeController @Inject()( + val controllerComponents: ControllerComponents, + corsAction: CORSAction +) extends BaseController { - /** - * Create an Action to render an HTML page. - * - * The configuration in the `routes` file means that this method - * will be called when the application receives a `GET` request with - * a path of `/`. - */ - def index(): Action[AnyContent] = Action { implicit request: Request[AnyContent] => + def index(): Action[AnyContent] = corsAction { implicit request => Ok(views.html.index()) } -} \ No newline at end of file +} diff --git a/build.sbt b/build.sbt index 8b88627..e40005d 100644 --- a/build.sbt +++ b/build.sbt @@ -6,9 +6,13 @@ lazy val root = (project in file(".")).enablePlugins(PlayScala) scalaVersion := "2.13.14" -libraryDependencies += guice +libraryDependencies ++= Seq( + guice, + filters +) libraryDependencies += "org.scalatestplus.play" %% "scalatestplus-play" % "7.0.0" % Test + // Adds additional packages into Twirl //TwirlKeys.templateImports += "com.example.controllers._" diff --git a/conf/application.conf b/conf/application.conf index 3c1ffc6..83484a5 100644 --- a/conf/application.conf +++ b/conf/application.conf @@ -1,3 +1,16 @@ play.filters.hosts { allowed = ["."] } + +play.filters.enabled += play.filters.headers.SecurityHeadersFilter + +play.filters.headers { + contentSecurityPolicy = "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; frame-ancestors 'self' https://jevalide.ca" +} + +play.filters.enabled += "play.filters.cors.CORSFilter" +play.filters.cors { + allowedOrigins = null // Allow all origins + allowedHttpMethods = ["GET", "POST", "PUT", "DELETE", "OPTIONS"] + allowedHttpHeaders = ["Accept", "Content-Type"] +}