package controllers import play.api.libs.json.{JsValue, Json} import play.api.libs.typedmap.TypedKey import play.api.mvc._ import scala.concurrent.{ExecutionContext, Future} object SecuredActions { private val SteamIdAttr: TypedKey[String] = TypedKey("steamId") /** Steam ID текущего авторизованного пользователя (если он есть в запросе). */ def steamId[A](request: Request[A]): Option[String] = request.attrs.get(SteamIdAttr) /** Steam ID текущего пользователя или "unknown", если его нет в запросе. */ def steamIdOrUnknown[A](request: Request[A]): String = steamId(request).getOrElse("unknown") } /** * Simple session-based authentication via Steam ID. * Used to protect admin panel routes. */ trait SecuredActions { self: AbstractController => private val SteamIdAttr: TypedKey[String] = SecuredActions.SteamIdAttr /** Wrapper that requires the user to be logged in with Steam. */ def Secured: ActionBuilder[Request, AnyContent] = securedWith(controllerComponents.parsers.defaultBodyParser, apiStyle = false) /** Same as [[Secured]], but parses the request body as JSON. */ def SecuredJson: ActionBuilder[Request, JsValue] = securedWith(controllerComponents.parsers.json, apiStyle = true) /** Same as [[Secured]], but answers AJAX calls with 401 JSON instead of a redirect. */ def SecuredApi: ActionBuilder[Request, AnyContent] = securedWith(controllerComponents.parsers.defaultBodyParser, apiStyle = true) private def securedWith[A](bodyParser: BodyParser[A], apiStyle: Boolean): ActionBuilder[Request, A] = new ActionBuilder[Request, A] { override def parser: BodyParser[A] = bodyParser override def executionContext: ExecutionContext = controllerComponents.executionContext override def invokeBlock[B](request: Request[B], block: Request[B] => Future[Result]): Future[Result] = request.session.get("steamId") match { case Some(steamId) => block(request.addAttr(SteamIdAttr, steamId)) case None if apiStyle => Future.successful(Unauthorized(Json.obj("error" -> "Please log in with Steam"))) case None => Future.successful(Redirect("/decider/admin/login").flashing("error" -> "Please log in with Steam")) } } }