package controllers.authentication import dao.AuthTokensDAO import jakarta.inject.Inject import models.{AuthToken, User} import play.api.libs.json.* import play.api.mvc.Results.Unauthorized import play.api.mvc.{ActionRefiner, Request, Result, WrappedRequest} import scala.concurrent.{ExecutionContext, Future} class AuthenticatedRequest[A](val token: AuthToken, val user: User, request: Request[A]) extends WrappedRequest[A](request) class AuthenticatedAction @Inject()(authTokensDao: AuthTokensDAO)(implicit val executionContext: ExecutionContext) extends ActionRefiner[Request, AuthenticatedRequest] { private final val tokenPrefix = "Token" override protected def refine[A](request: Request[A]): Future[Either[Result, AuthenticatedRequest[A]]] = { val authHeader = request.headers.get("Authorization") .flatMap { header => if header.startsWith(tokenPrefix) then Some(header.substring(tokenPrefix.length).trim) else None } .filter(_.nonEmpty) authHeader match { case Some(token) => authTokensDao.find(token).flatMap { case Some(authToken) => findUser(request, authToken) case None => Future.successful(unauthenticatedRequestError) } case None => Future.successful(unauthenticatedRequestError) } } private val unauthenticatedRequestError = Left(Unauthorized(Json.obj("error" -> "Unauthenticated"))) private def findUser[A](request: Request[A], token: AuthToken) = { authTokensDao.getUser(token).map { case Some(user) => Right(AuthenticatedRequest(token, user, request)) case None => unauthenticatedRequestError } } }