Compare commits

...
Sign in to create a new pull request.

1 commit

Author SHA1 Message Date
Joey Yakimowich-Payne
8b39358dd6 Allow passing of url between jester and frontend 2020-02-22 15:23:51 -07:00
5 changed files with 56 additions and 13 deletions

View file

@ -15,6 +15,7 @@
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=$ga"></script>
<script>
window.SERVER_URL = "$server_url";
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());

View file

@ -267,7 +267,9 @@ proc initialise() =
{
"title": config.title,
"timestamp": encodeUrl(CompileDate & CompileTime),
"ga": config.ga
"ga": config.ga,
# An ugly hack, maybe there's a better way?
"server_url": "$server_url"
}.newStringTable()
@ -1554,4 +1556,4 @@ routes:
get re"/(.*)":
cond request.matches[0].splitFile.ext == ""
resp karaxHtml
resp karaxHtml % {"server_url": request.url.jsEscape}.newStringTable

View file

@ -1,7 +1,8 @@
import options, tables, sugar, httpcore
import options, tables, sugar, httpcore, uri
from dom import window, Location, document, decodeURI
include karax/prelude
import karax/[kdom]
import jester/[patterns]
import threadlist, postlist, header, profile, newthread, error, about
@ -12,6 +13,7 @@ type
State = ref object
originalTitle: cstring
url: Location
serverUri: Uri
profile: ProfileState
newThread: NewThread
about: About
@ -36,6 +38,7 @@ proc newState(): State =
State(
originalTitle: document.title,
url: copyLocation(window.location),
serverUri: SERVER_URI,
profile: newProfileState(),
newThread: newNewThread(),
about: newAbout(),
@ -56,6 +59,7 @@ proc onPopState(event: dom.Event) =
state.url = copyLocation(window.location)
redraw()
window.location.reload()
type Params = Table[string, string]
type
@ -66,12 +70,12 @@ type
proc r(n: string, p: proc (params: Params): VNode): Route = Route(n: n, p: p)
proc route(routes: openarray[Route]): VNode =
let path =
if state.url.pathname.len == 0: "/" else: $state.url.pathname
if state.serverUri.path.len == 0: "/" else: state.serverUri.path
let prefix = if appName == "/": "" else: appName
for route in routes:
let pattern = (prefix & route.n).parsePattern()
var (matched, params) = pattern.match(path)
parseUrlQuery($state.url.search, params)
parseUrlQuery($state.serverUri.query, params)
if matched:
return route.p(params)

View file

@ -1,4 +1,4 @@
import strutils, strformat, parseutils, tables
import strutils, strformat, parseutils, tables, uri
proc parseIntSafe*(s: string, value: var int) {.noSideEffect.} =
## parses `s` into an integer in the range `validRange`. If successful,
@ -31,6 +31,10 @@ when defined(js):
const appName* = "/"
# Get the server URL that we set in the backend
var SERVER_URL* {.importc: "SERVER_URL".}: cstring
let SERVER_URI* = parseUri($SERVER_URL)
proc class*(classes: varargs[tuple[name: string, present: bool]],
defaultClasses: string = ""): string =
result = defaultClasses & " "
@ -42,11 +46,13 @@ when defined(js):
## Concatenates ``relative`` to the current URL in a way that is
## (possibly) sane.
var relative = relative
assert appName in $window.location.pathname
assert appName in SERVER_URI.path
if relative[0] == '/': relative = relative[1..^1]
return $window.location.protocol & "//" &
$window.location.host &
let port = if SERVER_URI.port.len > 0: ":" & SERVER_URI.port else: ""
return SERVER_URI.scheme & "://" &
SERVER_URI.hostname & port &
appName &
relative &
search &
@ -62,7 +68,7 @@ when defined(js):
query.add(param[0] & "=" & param[1])
if query.len > 0:
var search = if reuseSearch: $window.location.search else: ""
var search = if reuseSearch: SERVER_URI.query else: ""
if search.len != 0: search.add("&")
search.add(query)
if search[0] != '?': search = "?" & search
@ -86,6 +92,7 @@ when defined(js):
let url = n.getAttr("href")
navigateTo(url)
window.location.href = url
proc newFormData*(form: dom.Element): FormData
{.importcpp: "new FormData(@)", constructor.}

View file

@ -1,13 +1,21 @@
import asyncdispatch, smtp, strutils, json, os, rst, rstgen, xmltree, strtabs,
htmlparser, streams, parseutils, options, logging
import asyncdispatch, strutils, json, os, rst, rstgen, xmltree, strtabs,
htmlparser, streams, parseutils, logging, uri, options, nre, strformat
from times import getTime, getGMTime, format
import jester
import jester/private/utils as jesterutils
when useHttpBeast:
import httpbeast except Settings, Request
else:
import asynchttpserver
# Used to be:
# {'A'..'Z', 'a'..'z', '0'..'9', '_', '\128'..'\255'}
let
UsernameIdent* = IdentChars # TODO: Double check that everyone follows this.
import frontend/[karaxutils, error]
import frontend/[error]
export parseInt
type
@ -181,3 +189,24 @@ proc rstToHtml*(content: string): string =
add(result, node, indWidth=0, addNewLines=false)
except:
warn("Could not parse rst html.")
proc jsEscape*(str: string): string =
## Escapes a string to be stored in a JS variable. This prevents
## XSS attacks. Taken from here: https://portswigger.net/web-security/cross-site-scripting/preventing
str.replace(
re"[^\w. ]",
proc(match: string): string =
let code = match[0].ord
fmt"\u{code:04x}"
)
proc url*(request: Request): string =
## Get the full URL of the request, including the query params
let nativeRequest = request.getNativeReq
when useHttpBeast:
let query = nativeRequest.path.get("").parseUri().query
else:
let query = nativeRequest.url.query
let proto = if request.secure: "https" else: "http"
result = proto & "://" & request.host & request.path & query