Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 46 additions & 41 deletions app/controllers/Challenge.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package controllers

import play.api.libs.json.Json
import play.api.mvc.Result
import play.api.mvc.{ RequestHeader, Result }

import lila.app.{ *, given }
import lila.challenge.{ Challenge as ChallengeModel, Direction }
Expand Down Expand Up @@ -81,7 +81,8 @@ final class Challenge(env: Env) extends LilaController(env):

private def isMine(challenge: ChallengeModel)(using Context) =
challenge.challenger match
case lila.challenge.Challenge.Challenger.Anonymous(secret) => ctx.req.sid.contains(secret)
case lila.challenge.Challenge.Challenger.Anonymous(secret) =>
anonSecretFromCookieOrMobileSri.exists(_ == secret)
case lila.challenge.Challenge.Challenger.Registered(userId, _) => ctx.is(userId)
case lila.challenge.Challenge.Challenger.Open => false

Expand Down Expand Up @@ -193,50 +194,51 @@ final class Challenge(env: Env) extends LilaController(env):
then api.cancel(c).inject(NoContent)
else notFound

def apiCancel(id: ChallengeId) = Scoped(_.Challenge.Write, _.Bot.Play, _.Board.Play, _.Web.Mobile): ctx ?=>
me ?=>
api
.activeByIdBy(id, me)
def apiCancel(id: ChallengeId) =
AnonOrScoped(_.Challenge.Write, _.Bot.Play, _.Board.Play, _.Web.Mobile): ctx ?=>
(ctx.user orElse anonSecretFromCookieOrMobileSri)
.so(api.activeByIdBy(id, _))
.flatMap:
case Some(c) => api.cancel(c).inject(jsonOkResult)
case None =>
api
.activeByIdFor(id, me)
.flatMap:
case Some(c) => api.decline(c, ChallengeModel.DeclineReason.default).inject(jsonOkResult)
case None =>
import lila.core.round.{ Tell, RoundBus }
env.game.gameRepo
.game(id.into(GameId))
.dmap:
_.flatMap { Pov(_, me) }
.flatMapz: p =>
env.round.proxyRepo.upgradeIfPresent(p).dmap(some)
.flatMap:
case Some(pov) if pov.game.abortableByUser =>
lila.common.Bus.pub(Tell(pov.gameId, RoundBus.Abort(pov.playerId)))
jsonOkResult
case Some(pov) if pov.game.playable =>
Bearer.from(get("opponentToken")) match
case Some(bearer) =>
val required = OAuthScope.select(_.Challenge.Write).into(EndpointScopes)
allow:
for
access <- env.oAuth.server.auth(bearer, required, ctx.req.some)
_ <- raiseIf(!pov.opponent.isUser(access.me)):
OAuthServer.AuthError("Not the opponent token")
yield
ctx.me.soUse: me ?=>
api
.activeByIdFor(id, me)
.flatMap:
case Some(c) => api.decline(c, ChallengeModel.DeclineReason.default).inject(jsonOkResult)
case None =>
import lila.core.round.{ Tell, RoundBus }
env.game.gameRepo
.game(id.into(GameId))
.dmap:
_.flatMap { Pov(_, me) }
.flatMapz: p =>
env.round.proxyRepo.upgradeIfPresent(p).dmap(some)
.flatMap:
case Some(pov) if pov.game.abortableByUser =>
lila.common.Bus.pub(Tell(pov.gameId, RoundBus.Abort(pov.playerId)))
jsonOkResult
case Some(pov) if pov.game.playable =>
Bearer.from(get("opponentToken")) match
case Some(bearer) =>
val required = OAuthScope.select(_.Challenge.Write).into(EndpointScopes)
allow:
for
access <- env.oAuth.server.auth(bearer, required, ctx.req.some)
_ <- raiseIf(!pov.opponent.isUser(access.me)):
OAuthServer.AuthError("Not the opponent token")
yield
lila.common.Bus.pub(Tell(pov.gameId, RoundBus.AbortForce))
jsonOkResult
.rescue: err =>
BadRequest(jsonError(err.message))
case None if api.isOpenBy(id, me) =>
if pov.game.abortable then
lila.common.Bus.pub(Tell(pov.gameId, RoundBus.AbortForce))
jsonOkResult
.rescue: err =>
BadRequest(jsonError(err.message))
case None if api.isOpenBy(id, me) =>
if pov.game.abortable then
lila.common.Bus.pub(Tell(pov.gameId, RoundBus.AbortForce))
jsonOkResult
else BadRequest(jsonError("The game can no longer be aborted"))
case None => BadRequest(jsonError("Missing opponentToken"))
case _ => notFoundJson()
else BadRequest(jsonError("The game can no longer be aborted"))
case None => BadRequest(jsonError("Missing opponentToken"))
case _ => notFoundJson()

def apiStartClocks(id: GameId) = Anon:
Found(env.round.proxyRepo.game(id)): game =>
Expand Down Expand Up @@ -383,3 +385,6 @@ final class Challenge(env: Env) extends LilaController(env):
else BadRequest(jsonError("Sorry, couldn't create the rematch."))
}
}

private def anonSecretFromCookieOrMobileSri(using RequestHeader) =
req.sid orElse lila.security.Mobile.LichessMobileUa.sriFromUA.map(_.value)
18 changes: 9 additions & 9 deletions modules/challenge/src/main/ChallengeApi.scala
Original file line number Diff line number Diff line change
Expand Up @@ -68,15 +68,15 @@ final class ChallengeApi(

def activeByIdFor(id: ChallengeId, dest: User): Future[Option[Challenge]] =
repo.byIdFor(id, dest).dmap(_.filter(_.active))
def activeByIdBy(id: ChallengeId, maker: User): Future[Option[Challenge]] =
repo
.byId(id)
.dmap(_.filter { c =>
c.active && c.challenger.match
case Challenger.Registered(orig, _) if maker.is(orig) => true
case Challenger.Open if isOpenBy(id, maker) => true
case _ => false
})

def activeByIdBy(id: ChallengeId, by: User | String): Future[Option[Challenge]] =
for opt <- repo.byId(id)
yield opt.filter: c =>
c.active && (c.challenger, by).match
case (Challenger.Registered(orig, _), user: User) if user.is(orig) => true
case (Challenger.Open, user: User) if isOpenBy(id, user) => true
case (Challenger.Anonymous(secret), anonSecret: String) if secret == anonSecret => true
case _ => false

val countInFor = cacheApi[UserId, Int](131_072, "challenge.countInFor"):
_.expireAfterAccess(15.minutes).buildAsyncFuture(repo.countCreatedByDestId)
Expand Down
Loading