Skip to content

Commit

Permalink
Merge pull request #10737 from benediktwerner/team-forum-mod-access
Browse files Browse the repository at this point in the history
Prevent non-mod posts from mods in team forums without being a member
  • Loading branch information
ornicar authored Mar 30, 2022
2 parents 66a8f12 + 5f29a40 commit d3ec96e
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 26 deletions.
5 changes: 3 additions & 2 deletions app/controllers/ForumController.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@ private[controllers] trait ForumController { self: LilaController =>
protected def teamCache = env.team.cached

protected def CategGrantWrite[A <: Result](
categSlug: String
categSlug: String,
tryingToPostAsMod: Boolean = false
)(a: => Fu[A])(implicit ctx: Context): Fu[Result] =
access.isGrantedWrite(categSlug) flatMap { granted =>
access.isGrantedWrite(categSlug, tryingToPostAsMod) flatMap { granted =>
if (granted) a
else fuccess(Forbidden("You cannot post to this category"))
}
Expand Down
36 changes: 19 additions & 17 deletions app/controllers/ForumPost.scala
Original file line number Diff line number Diff line change
Expand Up @@ -27,35 +27,37 @@ final class ForumPost(env: Env) extends LilaController(env) with ForumController
def create(categSlug: String, slug: String, page: Int) =
AuthBody { implicit ctx => me =>
NoBot {
CategGrantWrite(categSlug) {
implicit val req = ctx.body
OptionFuResult(topicApi.show(categSlug, slug, page, ctx.me)) { case (categ, topic, posts) =>
if (topic.closed) fuccess(BadRequest("This topic is closed"))
else if (topic.isOld) fuccess(BadRequest("This topic is archived"))
else
categ.team.?? { env.team.cached.isLeader(_, me.id) } flatMap { inOwnTeam =>
forms
.post(me, inOwnTeam)
.bindFromRequest()
.fold(
err =>
implicit val req = ctx.body
OptionFuResult(topicApi.show(categSlug, slug, page, ctx.me)) { case (categ, topic, posts) =>
if (topic.closed) fuccess(BadRequest("This topic is closed"))
else if (topic.isOld) fuccess(BadRequest("This topic is archived"))
else
categ.team.?? { env.team.cached.isLeader(_, me.id) } flatMap { inOwnTeam =>
forms
.post(me, inOwnTeam)
.bindFromRequest()
.fold(
err =>
CategGrantWrite(categSlug, tryingToPostAsMod = true) {
for {
captcha <- forms.anyCaptcha
unsub <- env.timeline.status(s"forum:${topic.id}")(me.id)
canModCateg <- access.isGrantedMod(categ.slug)
} yield BadRequest(
html.forum.topic
.show(categ, topic, posts, Some(err -> captcha), unsub, canModCateg = canModCateg)
),
data =>
)
},
data =>
CategGrantWrite(categSlug, tryingToPostAsMod = ~data.modIcon) {
CreateRateLimit(ctx.ip) {
postApi.makePost(categ, topic, data, me) map { post =>
Redirect(routes.ForumPost.redirect(post.id))
}
}(rateLimitedFu)
)
}
}
}
)
}
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/ForumTopic.scala
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ final class ForumTopic(env: Env) extends LilaController(env) with ForumControlle
for {
unsub <- ctx.userId ?? env.timeline.status(s"forum:${topic.id}")
canRead <- access.isGrantedRead(categ.slug)
canWrite <- access.isGrantedWrite(categ.slug)
canWrite <- access.isGrantedWrite(categ.slug, tryingToPostAsMod = true)
canModCateg <- access.isGrantedMod(categ.slug)
inOwnTeam <- ~(categ.team, ctx.me).mapN { case (teamId, me) =>
env.team.cached.isLeader(teamId, me.id)
Expand Down
16 changes: 10 additions & 6 deletions modules/api/src/main/ForumAccess.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ final class ForumAccess(teamApi: lila.team.TeamApi, teamCached: lila.team.Cached
case object Read extends Operation
case object Write extends Operation

def isGranted(categSlug: String, op: Operation)(implicit ctx: UserContext): Fu[Boolean] =
private def isGranted(categSlug: String, op: Operation)(implicit ctx: UserContext): Fu[Boolean] =
Categ.slugToTeamId(categSlug).fold(fuTrue) { teamId =>
ctx.me ?? { me =>
fuccess(Granter(Permission.ModerateForum)(me)) >>| teamCached.forumAccess.get(teamId).flatMap {
teamCached.forumAccess.get(teamId).flatMap {
case Team.Access.NONE => fuFalse
case Team.Access.EVERYONE =>
op match {
Expand All @@ -34,10 +34,14 @@ final class ForumAccess(teamApi: lila.team.TeamApi, teamCached: lila.team.Cached
}

def isGrantedRead(categSlug: String)(implicit ctx: UserContext): Fu[Boolean] =
isGranted(categSlug, Read)

def isGrantedWrite(categSlug: String)(implicit ctx: UserContext): Fu[Boolean] =
ctx.me.exists(canWriteInAnyForum) ?? isGranted(categSlug, Write)
if (ctx.me ?? Granter(Permission.Shusher)) fuTrue
else isGranted(categSlug, Read)

def isGrantedWrite(categSlug: String, tryingToPostAsMod: Boolean = false)(implicit
ctx: UserContext
): Fu[Boolean] =
if (tryingToPostAsMod && ctx.me ?? Granter(Permission.Shusher)) fuTrue
else ctx.me.exists(canWriteInAnyForum) ?? isGranted(categSlug, Write)

private def canWriteInAnyForum(u: User) =
!u.isBot && {
Expand Down

0 comments on commit d3ec96e

Please sign in to comment.