Add redirect tag
authorLanius Trolling <lanius@laniustrolling.dev>
Mon, 12 Jun 2023 14:31:52 +0000 (10:31 -0400)
committerLanius Trolling <lanius@laniustrolling.dev>
Mon, 12 Jun 2023 14:31:52 +0000 (10:31 -0400)
build.gradle.kts
src/main/kotlin/info/mechyrdia/Factbooks.kt
src/main/kotlin/info/mechyrdia/lore/parser_tags.kt
src/main/kotlin/info/mechyrdia/lore/view_tpl.kt
src/main/resources/logback.xml
src/main/resources/static/init.js

index 50e2cc0cce7f9db21c7653c76c2e7b702a2d6111..b7b84ea33cfbbf40e66d1a821e052222ef497693 100644 (file)
@@ -41,19 +41,19 @@ dependencies {
        implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.6.4")
        implementation("org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.6.4")
        implementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactive:1.6.4")
-       implementation("org.jetbrains.kotlinx:kotlinx-serialization-core-jvm:1.4.1")
-       implementation("org.jetbrains.kotlinx:kotlinx-serialization-json-jvm:1.4.1")
+       implementation("org.jetbrains.kotlinx:kotlinx-serialization-core-jvm:1.5.0")
+       implementation("org.jetbrains.kotlinx:kotlinx-serialization-json-jvm:1.5.0")
        
-       implementation("io.ktor:ktor-server-core-jvm:2.3.0")
-       implementation("io.ktor:ktor-server-netty-jvm:2.3.0")
+       implementation("io.ktor:ktor-server-core-jvm:2.3.1")
+       implementation("io.ktor:ktor-server-netty-jvm:2.3.1")
        
-       implementation("io.ktor:ktor-server-call-id:2.3.0")
-       implementation("io.ktor:ktor-server-call-logging:2.3.0")
-       implementation("io.ktor:ktor-server-conditional-headers:2.3.0")
-       implementation("io.ktor:ktor-server-forwarded-header:2.3.0")
-       implementation("io.ktor:ktor-server-html-builder:2.3.0")
-       implementation("io.ktor:ktor-server-sessions-jvm:2.3.0")
-       implementation("io.ktor:ktor-server-status-pages:2.3.0")
+       implementation("io.ktor:ktor-server-call-id:2.3.1")
+       implementation("io.ktor:ktor-server-call-logging:2.3.1")
+       implementation("io.ktor:ktor-server-conditional-headers:2.3.1")
+       implementation("io.ktor:ktor-server-forwarded-header:2.3.1")
+       implementation("io.ktor:ktor-server-html-builder:2.3.1")
+       implementation("io.ktor:ktor-server-sessions-jvm:2.3.1")
+       implementation("io.ktor:ktor-server-status-pages:2.3.1")
        
        implementation("org.jetbrains.kotlinx:kotlinx-html-jvm:0.8.0")
        
@@ -71,8 +71,8 @@ dependencies {
                exclude("org.jetbrains.kotlinx", "kotlinx-serialization-core-jvm")
        }
        
-       implementation("org.slf4j:slf4j-api:1.7.36")
-       implementation("ch.qos.logback:logback-classic:1.3.5")
+       implementation("org.slf4j:slf4j-api:2.0.5")
+       implementation("ch.qos.logback:logback-classic:1.4.7")
 }
 
 java {
index 6ab8f1fb44549e203b8bdea86753645e7dcaa79f..6203e3339b57e31d6beb625b91f227123f6133ce 100644 (file)
@@ -6,7 +6,6 @@ import info.mechyrdia.auth.*
 import info.mechyrdia.data.*
 import info.mechyrdia.lore.*
 import io.ktor.http.*
-import io.ktor.http.content.*
 import io.ktor.server.application.*
 import io.ktor.server.engine.*
 import io.ktor.server.html.*
@@ -15,7 +14,6 @@ import io.ktor.server.netty.*
 import io.ktor.server.plugins.*
 import io.ktor.server.plugins.callid.*
 import io.ktor.server.plugins.callloging.*
-import io.ktor.server.plugins.conditionalheaders.*
 import io.ktor.server.plugins.forwardedheaders.*
 import io.ktor.server.plugins.statuspages.*
 import io.ktor.server.request.*
@@ -23,11 +21,9 @@ import io.ktor.server.response.*
 import io.ktor.server.routing.*
 import io.ktor.server.sessions.*
 import io.ktor.server.sessions.serialization.*
-import io.ktor.util.*
 import org.slf4j.event.Level
 import java.io.File
 import java.io.IOException
-import java.io.InputStream
 import java.util.concurrent.atomic.AtomicLong
 
 lateinit var application: Application
@@ -72,7 +68,8 @@ fun Application.factbooks() {
                        
                        serializer = KotlinxSessionSerializer(UserSession.serializer(), JsonStorageCodec)
                        
-                       cookie.extensions["SameSite"] = "lax"
+                       cookie.httpOnly = true
+                       cookie.extensions["SameSite"] = "Lax"
                        cookie.extensions["Secure"] = null
                }
        }
index a266ff6d59a4898f63db109fe14c426583b60ad1..ac9e1391bbb31999456d0edcdae412f2fb713976 100644 (file)
@@ -1,6 +1,7 @@
 package info.mechyrdia.lore
 
 import info.mechyrdia.Configuration
+import kotlinx.serialization.json.JsonPrimitive
 import java.io.File
 
 sealed class TextParserTagType<TContext> {
@@ -85,7 +86,7 @@ enum class TextParserFormattingTag(val type: TextParserTagType<Unit>) {
        ),
        H1(
                TextParserTagType.Indirect { _, content, _ ->
-                       "<h1>$content</h1>"
+                       "<h1>$content</h1><script>window.checkRedirectTarget();</script>"
                }
        ),
        H2(
@@ -254,6 +255,15 @@ enum class TextParserFormattingTag(val type: TextParserTagType<Unit>) {
                        "<a id=\"$anchor\" name=\"$anchor\"></a>"
                }
        ),
+       REDIRECT(
+               TextParserTagType.Indirect { _, content, _ ->
+                       val target = TextParserState.censorText(content)
+                       val url = if (target.startsWith('/')) "/lore$target" else "./$target"
+                       val string = JsonPrimitive(url).toString()
+                       
+                       "<script>window.factbookRedirect($string);</script>"
+               }
+       ),
        
        // Conlangs
        LANG(
index c8ac1f210168446f1a5bf64565351d2325f745d1..19c576d74af28ee46276082859d13d3e92fe51ab 100644 (file)
@@ -28,6 +28,17 @@ fun ApplicationCall.page(pageTitle: String, navBar: List<NavItem>? = null, sideb
                        
                        link(rel = "stylesheet", href = "/static/style.css")
                        
+                       request.queryParameters["redirect"]?.let { redirect ->
+                               if (redirect == "no")
+                                       script {
+                                               unsafe {
+                                                       raw("window.disableFactbookRedirect = true;")
+                                               }
+                                       }
+                       }
+                       
+                       script(src = "/static/init.js") {}
+                       
                        title {
                                +pageTitle
                        }
@@ -102,8 +113,6 @@ fun ApplicationCall.page(pageTitle: String, navBar: List<NavItem>? = null, sideb
                                        }
                                }
                        }
-                       
-                       script(src = "/static/init.js") {}
                }
        }
 }
index 64e2290221f3b4116ac6adfb1ded23ad9cde561c..a9f975ae694d4d3ae134b6e300a2b02a333c3bd5 100644 (file)
@@ -18,7 +18,7 @@
                </encoder>
        </appender>
 
-       <root level="any">
+       <root level="INFO">
                <appender-ref ref="STDOUT"/>
                <appender-ref ref="LOGDIR"/>
        </root>
index fb1726ff3db7dd9db2b6eec75275f83e9aeeb885..08d7627c24767c705fca4a29595874219500eb48 100644 (file)
                        });
                }
        });
+
+       window.factbookRedirect = function (redirectTo) {
+               if (window.disableFactbookRedirect) {
+                       const redirectTarget = new URL(redirectTo, window.location);
+
+                       const redirectTargetUrl = redirectTarget.pathname + redirectTarget.search + redirectTarget.hash;
+
+                       const pElement = document.createElement("p");
+                       pElement.style.fontWeight = "800";
+                       pElement.append(document.createTextNode("Redirect to "));
+
+                       const aElement = document.createElement("a");
+                       aElement.href = redirectTargetUrl;
+                       aElement.append(document.createTextNode(redirectTarget.pathname));
+
+                       pElement.append(aElement);
+                       document.currentScript.after(pElement);
+               } else {
+                       document.cookie = "RedirectedFrom=" + window.location.pathname + "; SameSite=Lax; Secure";
+                       window.location = redirectTo;
+               }
+       };
+
+       window.checkRedirectTarget = function () {
+               const redirectSourceValues = document.cookie.split(';').filter(value => value.trim().startsWith("RedirectedFrom="));
+               if (redirectSourceValues.length > 0) {
+                       const redirectSource = new URL(redirectSourceValues[0].trim().substring("RedirectedFrom=".length), window.location.origin);
+                       if (redirectSource.search.length > 0) {
+                               redirectSource.search += "&redirect=no";
+                       } else {
+                               redirectSource.search = "?redirect=no";
+                       }
+
+                       const redirectSourceUrl = redirectSource.pathname + redirectSource.search + redirectSource.hash;
+
+                       const pElement = document.createElement("p");
+                       pElement.style.fontSize = "0.8em";
+                       pElement.append(document.createTextNode("Redirected from "));
+
+                       const aElement = document.createElement("a");
+                       aElement.href = redirectSourceUrl;
+                       aElement.append(document.createTextNode(redirectSource.pathname));
+
+                       pElement.append(aElement);
+                       document.currentScript.after(pElement);
+               }
+
+               document.cookie = "RedirectedFrom=; Expires=Thu, 01 Jan 1970 00:00:00 GMT; SameSite=Lax; Secure";
+       };
 })();