simplify and randomize assets versions - closes #4561
Requires replacing the following nginx config: rewrite ^/assets/\d+/(.*)$ /assets/$1; with rewrite "^/assets/\w{6}/(.*)$" /assets/$1;pull/4616/head
parent
8d0f9f7794
commit
accb4b0cbd
|
@ -67,7 +67,6 @@ object Global extends GlobalSettings {
|
|||
fuccess(InternalServerError(views.html.base.errorPage(ex) {
|
||||
lila.api.Context.error(
|
||||
req,
|
||||
lila.common.AssetVersion(lila.app.Env.api.assetVersionSetting.get()),
|
||||
lila.i18n.defaultLang,
|
||||
HTTPRequest.isSynchronousHttp(req) option lila.common.Nonce.random
|
||||
)
|
||||
|
|
|
@ -14,7 +14,6 @@ object Dev extends LilaController {
|
|||
Env.security.ugcArmedSetting,
|
||||
Env.security.emailBlacklistSetting,
|
||||
Env.irwin.irwinModeSetting,
|
||||
Env.api.assetVersionSetting,
|
||||
Env.explorer.indexFlowSetting,
|
||||
Env.report.scoreThresholdSetting,
|
||||
Env.api.cspEnabledSetting
|
||||
|
|
|
@ -376,7 +376,7 @@ private[controllers] trait LilaController
|
|||
private def pageDataBuilder(ctx: UserContext, hasFingerprint: Boolean): Fu[PageData] = {
|
||||
val isPage = HTTPRequest isSynchronousHttp ctx.req
|
||||
val nonce = isPage option Nonce.random
|
||||
ctx.me.fold(fuccess(PageData.anon(ctx.req, getAssetVersion, nonce, blindMode(ctx)))) { me =>
|
||||
ctx.me.fold(fuccess(PageData.anon(ctx.req, nonce, blindMode(ctx)))) { me =>
|
||||
import lila.relation.actorApi.OnlineFriends
|
||||
Env.pref.api.getPref(me, ctx.req) zip {
|
||||
if (isPage) {
|
||||
|
@ -394,15 +394,12 @@ private[controllers] trait LilaController
|
|||
PageData(onlineFriends, teamNbRequests, nbChallenges, nbNotifications, pref,
|
||||
blindMode = blindMode(ctx),
|
||||
hasFingerprint = hasFingerprint,
|
||||
assetVersion = getAssetVersion,
|
||||
inquiry = inquiry,
|
||||
nonce = nonce)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected def getAssetVersion = lila.common.AssetVersion(Env.api.assetVersionSetting.get())
|
||||
|
||||
private def blindMode(implicit ctx: UserContext) =
|
||||
ctx.req.cookies.get(Env.api.Accessibility.blindCookieName) ?? { c =>
|
||||
c.value.nonEmpty && c.value == Env.api.Accessibility.hash
|
||||
|
|
|
@ -157,5 +157,5 @@ Disallow: /games/export
|
|||
Ok(html.site.getFishnet()).fuccess
|
||||
}
|
||||
|
||||
def versionedAsset(version: Int, file: String) = Assets.at(path = "/public", file)
|
||||
def versionedAsset(version: String, file: String) = Assets.at(path = "/public", file)
|
||||
}
|
||||
|
|
|
@ -96,8 +96,7 @@ object Tv extends LilaController {
|
|||
case Some(game) => Ok(views.html.tv.embed(
|
||||
Pov first game,
|
||||
get("bg", req) | "light",
|
||||
lila.pref.Theme(~get("theme", req)).cssClass,
|
||||
assetVersion = getAssetVersion
|
||||
lila.pref.Theme(~get("theme", req)).cssClass
|
||||
))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,44 +17,37 @@ trait AssetHelper { self: I18nHelper =>
|
|||
|
||||
val assetBaseUrl = s"//$assetDomain"
|
||||
|
||||
def assetUrl(path: String, version: AssetVersion): String =
|
||||
s"$assetBaseUrl/assets/$version/$path"
|
||||
def assetUrl(path: String)(implicit ctx: Context): String =
|
||||
assetUrl(path, ctx.pageData.assetVersion)
|
||||
def assetVersion = AssetVersion.current
|
||||
|
||||
def assetUrl(path: String): String =
|
||||
s"$assetBaseUrl/assets/$assetVersion/$path"
|
||||
|
||||
def cdnUrl(path: String) = s"$assetBaseUrl$path"
|
||||
def staticUrl(path: String) = s"$assetBaseUrl/assets/$path"
|
||||
|
||||
def dbImageUrl(path: String) = s"$assetBaseUrl/image/$path"
|
||||
|
||||
def cssTag(name: String)(implicit ctx: Context): Html =
|
||||
cssAt("stylesheets/" + name)
|
||||
def cssTag(name: String): Html = cssAt("stylesheets/" + name)
|
||||
|
||||
def cssVendorTag(name: String)(implicit ctx: Context) =
|
||||
cssAt("vendor/" + name)
|
||||
def cssVendorTag(name: String) = cssAt("vendor/" + name)
|
||||
|
||||
def cssAt(path: String, version: AssetVersion): Html = Html {
|
||||
val href = assetUrl(path, version)
|
||||
s"""<link href="$href" type="text/css" rel="stylesheet"/>"""
|
||||
def cssAt(path: String): Html = Html {
|
||||
s"""<link href="${assetUrl(path)}" type="text/css" rel="stylesheet"/>"""
|
||||
}
|
||||
def cssAt(path: String)(implicit ctx: Context): Html =
|
||||
cssAt(path, ctx.pageData.assetVersion)
|
||||
|
||||
def jsTag(name: String, async: Boolean = false)(implicit ctx: Context) =
|
||||
def jsTag(name: String, async: Boolean = false) =
|
||||
jsAt("javascripts/" + name, async = async)
|
||||
|
||||
def jsAt(path: String, async: Boolean, version: AssetVersion): Html = Html {
|
||||
val src = assetUrl(path, version)
|
||||
def jsAt(path: String, async: Boolean = false): Html = Html {
|
||||
val src = assetUrl(path)
|
||||
s"""<script${if (async) " async defer" else ""} src="$src"></script>"""
|
||||
}
|
||||
def jsAt(path: String, async: Boolean = false)(implicit ctx: Context): Html =
|
||||
jsAt(path, async, ctx.pageData.assetVersion)
|
||||
|
||||
val jQueryTag = Html {
|
||||
s"""<script src="${staticUrl("javascripts/vendor/jquery.min.js")}"></script>"""
|
||||
}
|
||||
|
||||
def roundTag(implicit ctx: Context) =
|
||||
def roundTag =
|
||||
jsAt(s"compiled/lichess.round${isProd ?? (".min")}.js", async = true)
|
||||
|
||||
val highchartsLatestTag = Html {
|
||||
|
|
|
@ -50,7 +50,7 @@ csp: Option[lila.common.ContentSecurityPolicy] = None)(body: Html)(implicit ctx:
|
|||
@if(ctx.userContext.impersonatedBy.isDefined) { @cssTag("impersonate.css") }
|
||||
@if(isStage) { @cssTag("stage.css") }
|
||||
@moreCss
|
||||
<link id="piece-sprite" href="@staticUrl(s"stylesheets/piece/${ctx.currentPieceSet}.css?v=${ctx.pageData.assetVersion}")" type="text/css" rel="stylesheet"/>
|
||||
<link id="piece-sprite" href="@staticUrl(s"stylesheets/piece/${ctx.currentPieceSet}.css?v=$assetVersion")" type="text/css" rel="stylesheet"/>
|
||||
<meta content="@openGraph.fold(trans.siteDescription.txt())(o => o.description)" name="description">
|
||||
<link id="favicon" rel="shortcut icon" href="@staticUrl("images/favicon-32-white.png")" type="image/x-icon" />
|
||||
<link rel="mask-icon" href="@staticUrl("favicon.svg")" color="black">
|
||||
|
@ -84,7 +84,7 @@ csp: Option[lila.common.ContentSecurityPolicy] = None)(body: Html)(implicit ctx:
|
|||
data-sound-set="@ctx.currentSoundSet"
|
||||
data-socket-domain="@socketDomain"
|
||||
data-asset-url="@assetBaseUrl"
|
||||
data-asset-version="@ctx.pageData.assetVersion"
|
||||
data-asset-version="@assetVersion"
|
||||
@ctx.nonce.map { nonce => data-nonce="@nonce" }
|
||||
@ctx.zoom.map { zoom => data-zoom="@zoom" }>
|
||||
<form id="blind_mode" action="@routes.Main.toggleBlindMode" method="POST"><input type="hidden" name="enable" value="@if(ctx.blindMode){0}else{1}" /><input type="hidden" name="redirect" value="@ctx.req.path" /><button type="submit">Accessibility: @if(ctx.blindMode){Disable}else{Enable} blind mode</button></form>
|
||||
|
|
|
@ -45,7 +45,8 @@
|
|||
@base.form.input(form("command"))
|
||||
</form>
|
||||
<h2>Command examples:</h2>
|
||||
<pre>puzzle disable 70000
|
||||
<pre>change asset version
|
||||
puzzle disable 70000
|
||||
team disable foobar
|
||||
team enable foobar
|
||||
fishnet client create {username} analysis
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
@(pov: Pov, bg: String, theme: String, assetVersion: lila.common.AssetVersion)(implicit req: RequestHeader)
|
||||
@(pov: Pov, bg: String, theme: String)(implicit req: RequestHeader)
|
||||
|
||||
<!doctype html>
|
||||
<html>
|
||||
|
@ -7,11 +7,11 @@
|
|||
<meta name="Content-Security-Policy" content="@basicCsp">
|
||||
<title>lichess.org TV</title>
|
||||
@if(bg == "dark") {
|
||||
@cssAt("stylesheets/dark.css", assetVersion)
|
||||
@cssAt("stylesheets/dark.css")
|
||||
}
|
||||
@cssAt(s"stylesheets/piece/merida.css", assetVersion)
|
||||
@cssAt("stylesheets/common.css", assetVersion)
|
||||
@cssAt("stylesheets/board.css", assetVersion)
|
||||
@cssAt(s"stylesheets/piece/merida.css")
|
||||
@cssAt("stylesheets/common.css")
|
||||
@cssAt("stylesheets/board.css")
|
||||
</head>
|
||||
<body
|
||||
class="base highlight @bg"
|
||||
|
@ -22,7 +22,7 @@
|
|||
@game.vstext(pov)(none)
|
||||
</div>
|
||||
@jQueryTag
|
||||
@jsAt("javascripts/vendor/chessground.min.js", false, assetVersion)
|
||||
@jsAt("compiled/tv.js", false, assetVersion)
|
||||
@jsAt("javascripts/vendor/chessground.min.js", false)
|
||||
@jsAt("compiled/tv.js", false)
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -9,10 +9,7 @@ net {
|
|||
protocol = "http://"
|
||||
base_url = ${net.protocol}${net.domain}
|
||||
ip = "5.196.91.160"
|
||||
asset {
|
||||
domain = "lichess-assets.local"
|
||||
version = 2108
|
||||
}
|
||||
asset.domain = "lichess-assets.local"
|
||||
email = "contact@lichess.org"
|
||||
crawlable = false
|
||||
}
|
||||
|
|
|
@ -611,7 +611,7 @@ POST /jslog/$id<\w{12}> controllers.Main.jslog(id: String)
|
|||
POST /jsmon/:event controllers.Main.jsmon(event: String)
|
||||
|
||||
# Assets
|
||||
GET /assets/$version<\d+>/*file controllers.Main.versionedAsset(version: Int, file: String)
|
||||
GET /assets/$version<\d+>/*file controllers.Main.versionedAsset(version: String, file: String)
|
||||
GET /assets/*file controllers.Assets.at(path="/public", file)
|
||||
|
||||
GET /robots.txt controllers.Main.robots
|
||||
|
|
|
@ -18,6 +18,10 @@ private[api] final class Cli(bus: lila.common.Bus) extends lila.common.Cli {
|
|||
case "uptime" :: Nil => fuccess(lila.common.PlayApp.uptime.toStandardSeconds.getSeconds.toString)
|
||||
case "deploy" :: "pre" :: Nil => remindDeploy(lila.hub.actorApi.DeployPre)
|
||||
case "deploy" :: "post" :: Nil => remindDeploy(lila.hub.actorApi.DeployPost)
|
||||
case "change" :: ("asset" | "assets") :: "version" :: Nil =>
|
||||
import lila.common.AssetVersion
|
||||
AssetVersion.change
|
||||
fuccess(s"Changed to ${AssetVersion.current}")
|
||||
case "gdpr" :: "erase" :: username :: "forever" :: Nil =>
|
||||
lila.user.UserRepo named username flatMap {
|
||||
case None => fuccess("No such user.")
|
||||
|
|
|
@ -3,7 +3,7 @@ package lila.api
|
|||
import play.api.mvc.RequestHeader
|
||||
import play.api.i18n.Lang
|
||||
|
||||
import lila.common.{ HTTPRequest, AssetVersion, Nonce }
|
||||
import lila.common.{ HTTPRequest, Nonce }
|
||||
import lila.pref.Pref
|
||||
import lila.relation.actorApi.OnlineFriends
|
||||
import lila.user.{ UserContext, HeaderUserContext, BodyUserContext }
|
||||
|
@ -16,7 +16,6 @@ case class PageData(
|
|||
pref: Pref,
|
||||
blindMode: Boolean,
|
||||
hasFingerprint: Boolean,
|
||||
assetVersion: AssetVersion,
|
||||
inquiry: Option[lila.mod.Inquiry],
|
||||
nonce: Option[Nonce],
|
||||
error: Boolean = false
|
||||
|
@ -24,7 +23,7 @@ case class PageData(
|
|||
|
||||
object PageData {
|
||||
|
||||
def anon(req: RequestHeader, v: AssetVersion, nonce: Option[Nonce], blindMode: Boolean = false) = PageData(
|
||||
def anon(req: RequestHeader, nonce: Option[Nonce], blindMode: Boolean = false) = PageData(
|
||||
OnlineFriends.empty,
|
||||
teamNbRequests = 0,
|
||||
nbChallenges = 0,
|
||||
|
@ -32,12 +31,11 @@ object PageData {
|
|||
lila.pref.RequestPref fromRequest req,
|
||||
blindMode = blindMode,
|
||||
hasFingerprint = false,
|
||||
assetVersion = v,
|
||||
inquiry = none,
|
||||
nonce = nonce
|
||||
)
|
||||
|
||||
def error(req: RequestHeader, v: AssetVersion, nonce: Option[Nonce]) = anon(req, v, nonce).copy(error = true)
|
||||
def error(req: RequestHeader, nonce: Option[Nonce]) = anon(req, nonce).copy(error = true)
|
||||
}
|
||||
|
||||
sealed trait Context extends lila.user.UserContextWrapper {
|
||||
|
@ -101,8 +99,8 @@ final class HeaderContext(
|
|||
|
||||
object Context {
|
||||
|
||||
def error(req: RequestHeader, v: AssetVersion, lang: Lang, nonce: Option[Nonce]): HeaderContext =
|
||||
new HeaderContext(UserContext(req, none, none, lang), PageData.error(req, v, nonce))
|
||||
def error(req: RequestHeader, lang: Lang, nonce: Option[Nonce]): HeaderContext =
|
||||
new HeaderContext(UserContext(req, none, none, lang), PageData.error(req, nonce))
|
||||
|
||||
def apply(userContext: HeaderUserContext, pageData: PageData): HeaderContext =
|
||||
new HeaderContext(userContext, pageData)
|
||||
|
|
|
@ -60,13 +60,6 @@ final class Env(
|
|||
private val InfluxEventEndpoint = config getString "api.influx_event.endpoint"
|
||||
private val InfluxEventEnv = config getString "api.influx_event.env"
|
||||
|
||||
val assetVersionSetting = settingStore[Int](
|
||||
"assetVersion",
|
||||
default = config getInt "net.asset.version",
|
||||
text = "Assets version. Increment to force all clients to load a new version of static assets. Decrement to serve a previous revision of static assets.".some,
|
||||
init = (config, db) => config.value max db.value
|
||||
)
|
||||
|
||||
val cspEnabledSetting = settingStore[Boolean](
|
||||
"cspEnabled",
|
||||
default = true,
|
||||
|
|
|
@ -6,7 +6,13 @@ case class ApiVersion(value: Int) extends AnyVal with IntValue {
|
|||
def v3 = value == 3
|
||||
}
|
||||
|
||||
case class AssetVersion(value: Int) extends AnyVal with IntValue
|
||||
case class AssetVersion(value: String) extends AnyVal with StringValue
|
||||
|
||||
object AssetVersion {
|
||||
var current = random
|
||||
def change = { current = random }
|
||||
private def random = AssetVersion(ornicar.scalalib.Random nextString 6)
|
||||
}
|
||||
|
||||
case class MaxPerPage(value: Int) extends AnyVal with IntValue
|
||||
|
||||
|
|
Loading…
Reference in New Issue