diff --git a/.gitmodules b/.gitmodules index c2b11ee511..51d2845012 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,9 +4,6 @@ [submodule "public/vendor/tagmanager"] path = public/vendor/tagmanager url = https://github.com/max-favilli/tagmanager -[submodule "submodules/pdfexporter"] - path = submodules/pdfexporter - url = https://github.com/ornicar/lichessPDFExporter [submodule "ui/chessli"] path = ui/chessli url = https://github.com/ornicar/chess.js diff --git a/README.md b/README.md index 8f97e6832f..56beba1ffa 100644 --- a/README.md +++ b/README.md @@ -217,7 +217,7 @@ name | type | default | description "clock":{ // all clock values are expressed in seconds "initial": 300, "increment": 8, - "totalTime": 540 // evaluation of the game duration = initial + 30 * increment + "totalTime": 620 // evaluation of the game duration = initial + 40 * increment }, "createdAt": 1389100907239, "lastMoveAt": 1389100907239, @@ -300,7 +300,7 @@ name | type | default | description "clock":{ // all clock values are expressed in seconds "initial": 300, "increment": 8, - "totalTime": 540 // evaluation of the game duration = initial + 30 * increment + "totalTime": 620 // evaluation of the game duration = initial + 40 * increment }, "createdAt": 1389100907239, "lastMoveAt": 1389100907239, diff --git a/app/controllers/Auth.scala b/app/controllers/Auth.scala index cdfc2ec10f..bccf7b887a 100644 --- a/app/controllers/Auth.scala +++ b/app/controllers/Auth.scala @@ -96,8 +96,9 @@ object Auth extends LilaController { } } - private def mustConfirmEmailByIP(ip: String): Fu[Boolean] = - api.recentByIpExists(ip) >>| + private def mustConfirmEmailByIP(ip: String, username: String): Fu[Boolean] = + fuccess(username.toLowerCase.contains("argeskent")) >>| + api.recentByIpExists(ip) >>| Mod.ipIntelCache(ip).map(80 <).recover { case _: Exception => false } def signupPost = OpenBody { implicit ctx => @@ -110,7 +111,10 @@ object Auth extends LilaController { data => env.recaptcha.verify(~data.recaptchaResponse, req).flatMap { case false => BadRequest(html.auth.signup(forms.signup.website fill data, env.RecaptchaPublicKey)).fuccess case true => - mustConfirmEmailByIP(HTTPRequest lastRemoteAddress ctx.req) flatMap { mustConfirmEmail => + mustConfirmEmailByIP( + ip = HTTPRequest lastRemoteAddress ctx.req, + username = data.username + ) flatMap { mustConfirmEmail => lila.mon.user.register.website() lila.mon.user.register.mustConfirmEmail(mustConfirmEmail)() val email = env.emailAddress.validate(data.email) err s"Invalid email ${data.email}" @@ -172,21 +176,20 @@ object Auth extends LilaController { html = Unauthorized(html.auth.tor()).fuccess, api = _ => Unauthorized(jsonError("Can't login from Tor, sorry!")).fuccess) - def setFingerprint(fp: String, ms: Int) = Auth { ctx => - me => - api.setFingerprint(ctx.req, fp) flatMap { - _ ?? { hash => - !me.lame ?? { - api.recentUserIdsByFingerprint(hash).map(_.filter(me.id!=)) flatMap { - case otherIds if otherIds.size >= 2 => UserRepo countEngines otherIds flatMap { - case nb if nb >= 2 && nb >= otherIds.size / 2 => Env.report.api.autoCheatPrintReport(me.id) - case _ => funit - } - case _ => funit + def setFingerprint(fp: String, ms: Int) = Auth { ctx => me => + api.setFingerprint(ctx.req, fp) flatMap { + _ ?? { hash => + !me.lame ?? { + api.recentUserIdsByFingerprint(hash).map(_.filter(me.id!=)) flatMap { + case otherIds if otherIds.size >= 2 => UserRepo countEngines otherIds flatMap { + case nb if nb >= 2 && nb >= otherIds.size / 2 => Env.report.api.autoCheatPrintReport(me.id) + case _ => funit } + case _ => funit } } - } inject Ok + } + } inject Ok } def passwordReset = Open { implicit ctx => diff --git a/app/controllers/Export.scala b/app/controllers/Export.scala index 66c79091c5..76a9820de3 100644 --- a/app/controllers/Export.scala +++ b/app/controllers/Export.scala @@ -43,25 +43,6 @@ object Export extends LilaController { }) } - private val PdfRateLimitGlobal = new lila.memo.RateLimit( - credits = 20, - duration = 1 minute, - name = "export PDF global", - key = "export.pdf.global") - - def pdf(id: String) = Open { implicit ctx => - OnlyHumans { - PdfRateLimitGlobal("-", msg = HTTPRequest lastRemoteAddress ctx.req) { - lila.mon.export.pdf() - OptionResult(GameRepo game id) { game => - Ok.chunked(Enumerator.outputStream(env.pdfExport(game.id))).withHeaders( - CONTENT_TYPE -> "application/pdf", - CACHE_CONTROL -> "max-age=7200") - } - } - } - } - private val PngRateLimitGlobal = new lila.memo.RateLimit( credits = 60, duration = 1 minute, diff --git a/app/controllers/LilaController.scala b/app/controllers/LilaController.scala index 3379676184..8180505b36 100644 --- a/app/controllers/LilaController.scala +++ b/app/controllers/LilaController.scala @@ -48,6 +48,9 @@ private[controllers] trait LilaController protected def NoCache(res: Result): Result = res.withHeaders( CACHE_CONTROL -> "no-cache, no-store, must-revalidate", EXPIRES -> "0" ) + protected def NoIframe(res: Result): Result = res.withHeaders( + "X-Frame-Options" -> "SAMEORIGIN" + ) protected def Socket[A: FrameFormatter](f: Context => Fu[(Iteratee[A, _], Enumerator[A])]) = WebSocket.tryAccept[A] { req => diff --git a/app/controllers/Mod.scala b/app/controllers/Mod.scala index 3f4b471586..356311138b 100644 --- a/app/controllers/Mod.scala +++ b/app/controllers/Mod.scala @@ -97,7 +97,7 @@ object Mod extends LilaController { ModExternalBot { OptionFuResult(UserRepo named username) { user => Env.mod.jsonView(user) flatMap { - case None => NotFound.fuccess + case None => NotFound.fuccess case Some(data) => Env.mod.userHistory(user) map { history => Ok(data + ("history" -> history)) } @@ -137,7 +137,8 @@ object Mod extends LilaController { val url = s"http://check.getipintel.net/check.php?ip=$ip&contact=$email" WS.url(url).get().map(_.body).mon(_.security.proxy.request.time).flatMap { str => parseFloatOption(str).fold[Fu[Int]](fufail(s"Invalid ratio ${str.take(140)}")) { ratio => - fuccess((ratio * 100).toInt) + if (ratio < 0) fufail(s"Error code $ratio") + else fuccess((ratio * 100).toInt) } }.addEffects( fail = _ => lila.mon.security.proxy.request.failure(), diff --git a/app/controllers/Tv.scala b/app/controllers/Tv.scala index 3372814830..620fc23f75 100644 --- a/app/controllers/Tv.scala +++ b/app/controllers/Tv.scala @@ -37,14 +37,16 @@ object Tv extends LilaController { val onTv = lila.round.OnTv(channel.key, flip) negotiate( html = { - Env.api.roundApi.watcher(pov, lila.api.Mobile.Api.currentVersion, tv = onTv.some) zip - Env.game.crosstableApi(game) zip - Env.tv.tv.getChampions map { - case ((data, cross), champions) => NoCache { + Env.api.roundApi.watcher(pov, lila.api.Mobile.Api.currentVersion, tv = onTv.some) zip + Env.game.crosstableApi(game) zip + Env.tv.tv.getChampions map { + case ((data, cross), champions) => NoCache { + NoIframe { // can be heavy as TV reloads for each game Ok(html.tv.index(channel, champions, pov, data, cross, flip, history)) } } - }, + } + }, api = apiVersion => Env.api.roundApi.watcher(pov, apiVersion, tv = onTv.some) map { Ok(_) } ) } diff --git a/app/controllers/User.scala b/app/controllers/User.scala index e208010026..645731c617 100644 --- a/app/controllers/User.scala +++ b/app/controllers/User.scala @@ -21,6 +21,7 @@ object User extends LilaController { private def gamePaginator = Env.game.paginator private def forms = lila.user.DataForm private def relationApi = Env.relation.api + private def ratingChartApi = Env.history.ratingChartApi private def userGameSearch = Env.gameSearch.userGameSearch def tv(username: String) = Open { implicit ctx => @@ -192,7 +193,7 @@ object User extends LilaController { } def top200(perfKey: String) = Open { implicit ctx => - lila.rating.PerfType(perfKey).fold(notFound) { perfType => + PerfType(perfKey).fold(notFound) { perfType => env.cached top200Perf perfType.id map { users => Ok(html.user.top200(perfType, users)) } @@ -276,7 +277,7 @@ object User extends LilaController { def perfStat(username: String, perfKey: String) = Open { implicit ctx => OptionFuResult(UserRepo named username) { u => if ((u.disabled || (u.lame && !ctx.is(u))) && !isGranted(_.UserSpy)) notFound - else lila.rating.PerfType(perfKey).fold(notFound) { perfType => + else PerfType(perfKey).fold(notFound) { perfType => for { perfStat <- Env.perfStat.get(u, perfType) ranks <- Env.user.cached.ranking.getAll(u.id) @@ -286,7 +287,13 @@ object User extends LilaController { data = Env.perfStat.jsonView(u, perfStat, ranks get perfType.key, distribution) response <- negotiate( html = Ok(html.user.perfStat(u, ranks, perfType, data)).fuccess, - api = _ => Ok(data).fuccess) + api = _ => + getBool("graph").?? { + Env.history.ratingChartApi.singlePerf(u, perfType).map(_.some) + } map { + _.fold(data) { graph => data + ("graph" -> graph) } + } map { Ok(_) } + ) } yield response } } diff --git a/app/templating/SetupHelper.scala b/app/templating/SetupHelper.scala index 92732ae6d6..89d7088c82 100644 --- a/app/templating/SetupHelper.scala +++ b/app/templating/SetupHelper.scala @@ -61,6 +61,7 @@ trait SetupHelper { self: I18nHelper => variantTuple(chess.variant.Chess960) :+ variantTuple(chess.variant.KingOfTheHill) :+ variantTuple(chess.variant.ThreeCheck) :+ + variantTuple(chess.variant.Antichess) :+ variantTuple(chess.variant.Atomic) :+ variantTuple(chess.variant.Horde) :+ variantTuple(chess.variant.RacingKings) :+ diff --git a/app/views/analyse/replay.scala.html b/app/views/analyse/replay.scala.html index 75b102502d..37d04b31c1 100644 --- a/app/views/analyse/replay.scala.html +++ b/app/views/analyse/replay.scala.html @@ -73,9 +73,6 @@ atom = atom.some) { @if(game.isPgnImport) { @trans.downloadImported() } - @if(false) { - @trans.printFriendlyPDF() - } @if(false && lila.game.Game.visualisableVariants(game.variant)) { Generate images } diff --git a/app/views/analyse/replayBot.scala.html b/app/views/analyse/replayBot.scala.html index ae22764d2a..db72e7a488 100644 --- a/app/views/analyse/replayBot.scala.html +++ b/app/views/analyse/replayBot.scala.html @@ -84,8 +84,6 @@ chessground = true) { / @trans.downloadImported() } - / - @trans.printFriendlyPDF()
Would you like to watch
a live game while you wait?
This can take a while,
maybe reload this page later!