diff --git a/src/application-globals.rkt b/src/application-globals.rkt index 26cd6ae..5884804 100644 --- a/src/application-globals.rkt +++ b/src/application-globals.rkt @@ -163,11 +163,13 @@ #:head-data [head-data-in #f] #:siteinfo [siteinfo-in #f] #:user-cookies [user-cookies-in #f] - #:online-styles [online-styles #t]) + #:online-styles [online-styles #t] + #:path [path-in #f]) (define siteinfo (or siteinfo-in siteinfo-default)) (define head-data (or head-data-in ((head-data-getter wikiname)))) (define user-cookies (or user-cookies-in (user-cookies-getter req))) (define origin (format "https://~a.fandom.com" wikiname)) + (define path (or path-in "")) (define required-styles (cond [online-styles @@ -197,7 +199,8 @@ (link (@ (rel "stylesheet") (type "text/css") (href ,(get-static-url "main.css")))) (script "const BWData = " ,(jsexpr->string (hasheq 'wikiname wikiname - 'strict_proxy (config-true? 'strict_proxy)))) + 'strict_proxy (config-true? 'strict_proxy) + 'path path))) ,(if (config-true? 'feature_search_suggestions) `(script (@ (type "module") (src ,(get-static-url "search-suggestions.js")))) "") diff --git a/src/page-captcha.rkt b/src/page-captcha.rkt index 91889b6..3c8f2f5 100644 --- a/src/page-captcha.rkt +++ b/src/page-captcha.rkt @@ -92,7 +92,7 @@ (link (@ (rel "stylesheet") (type "text/css") (href ,(get-static-url "internal.css")))) (link (@ (rel "stylesheet") (type "text/css") (href ,(get-static-url "main.css")))) (link (@ (rel "icon") (href ,(head-data^-icon-url head-data-default)))) - (script (@ (defer) (src "/static/captcha.js"))) + (script (@ (defer) (src ,(get-static-url "captcha.js")))) (body (@ (class "skin-fandomdesktop theme-fandomdesktop-light internal")) (div (@ (class "main-container")) (div (@ (class "fandom-community-header__background tileBoth header"))) diff --git a/src/page-wiki-jsonp.rkt b/src/page-wiki-jsonp.rkt index 7ff425b..0c7918c 100644 --- a/src/page-wiki-jsonp.rkt +++ b/src/page-wiki-jsonp.rkt @@ -30,7 +30,7 @@ ("prop" . "text|headhtml|langlinks") ("formatversion" . "2") ("format" . "json") - ("callback" . "wikiPageCallback"))))) + ("callback" . "proxy.wikipage"))))) (define siteinfo-script-url (format "https://~a.fandom.com/api.php?~a" wikiname @@ -39,27 +39,29 @@ ("siprop" . "general|rightsinfo") ("format" . "json") ("formatversion" . "2") - ("callback" . "siteinfoCallback"))))) + ("callback" . "proxy.siteinfo"))))) (define body (generate-wiki-page `(div (noscript "You have to enable JavaScript to load wiki pages. Sorry!") (div (@ (id "loading"))) - (progress (@ (id "progress") (style "margin-bottom: 50vh"))) - (script ,(format #< obj[prop] = value }}) END - wikiname path)) - (script (@ (src ,(get-static-url "jsonp.js")))) + ) (script (@ (async) (src ,wiki-page-script-url))) - (script (@ (async) (src ,siteinfo-script-url)))) + (script (@ (async) (src ,siteinfo-script-url))) + (script (@ (type "module") (src ,(get-static-url "jsonp.js"))))) #:req req #:source-url source-url #:wikiname wikiname #:title (url-segments->guess-title segments) - #:siteinfo siteinfo-default)) + #:siteinfo siteinfo-default + #:path path)) (when (config-true? 'debug) (xexp->html body)) (response/output diff --git a/src/page-wiki.rkt b/src/page-wiki.rkt index 707157a..1caf41d 100644 --- a/src/page-wiki.rkt +++ b/src/page-wiki.rkt @@ -97,19 +97,37 @@ (define (page-wiki-with-data req) (response-handler - (define post-data/bytes (request-post-data/raw req)) - (when (not post-data/bytes) - (raise-user-error 'page-wiki-with-data "POST requests only, please.")) - (define post-data/string (bytes->string/utf-8 post-data/bytes)) - (define post-data (string->jsexpr post-data/string)) - (define wikiname (jp "/wikiname" post-data)) - (define path (jp "/path" post-data)) - (take-json-rewrite-and-return-page - #:req req - #:wikiname wikiname - #:source-url (format "https://~a.fandom.com/wiki/~a" wikiname path) - #:data (jp "/data" post-data) - #:siteinfo (data->siteinfo (jp "/siteinfo" post-data))))) + (let/cc return + (define post-data/bytes (request-post-data/raw req)) + (when (not post-data/bytes) + (return (response/jsexpr + #:code 400 + #:headers always-headers + '#hasheq((error . + #hasheq((code . "breezewiki") + (info . "POST requests only, please."))))))) + + (define origin-header + (or (headers-assq* #"origin" (request-headers/raw req)) + (headers-assq* #"referer" (request-headers/raw req)))) + (when (or (not origin-header) (not (string-prefix? (bytes->string/latin-1 (header-value origin-header)) (config-get 'canonical_origin)))) + (return (response/jsexpr + #:code 400 + #:headers always-headers + '#hasheq((error . + #hasheq((code . "breezewiki") + (info . "Origin/Referer header failed validation - cross-origin requests are not allowed here"))))))) + + (define post-data/string (bytes->string/utf-8 post-data/bytes)) + (define post-data (string->jsexpr post-data/string)) + (define wikiname (jp "/wikiname" post-data)) + (define path (jp "/path" post-data)) + (take-json-rewrite-and-return-page + #:req req + #:wikiname wikiname + #:source-url (format "https://~a.fandom.com/wiki/~a" wikiname path) + #:data (jp "/data" post-data) + #:siteinfo (data->siteinfo (jp "/siteinfo" post-data)))))) (define (take-json-rewrite-and-return-page #:req req #:wikiname wikiname #:source-url source-url #:data data #:siteinfo siteinfo) (define title (jp "/parse/title" data "")) diff --git a/static/jsonp.js b/static/jsonp.js index 4ed99de..851f86e 100644 --- a/static/jsonp.js +++ b/static/jsonp.js @@ -1,21 +1,40 @@ -const loading = document.getElementById("loading") -loading.textContent = "Loading, please wait..." -const progress = document.getElementById("progress") +import {h, htm, render, signal, computed, effect} from "./preact.js" +const html = htm.bind(h) -let wikiPage = null -function wikiPageCallback(data) { - wikiPage = data - cont() -} +// *** Loading indicator -let siteinfo = null -function siteinfoCallback(data) { - siteinfo = data - cont() -} +render(html`Loading, please wait...`, document.getElementById("loading")) + +// *** Progress bar + +const progress = signal(null) + +const progressBar = document.getElementById("progress-bar") +while (progressBar.childNodes[0] !== undefined) progressBar.childNodes[0].remove() // clear out loading indicators + +render(html``, progressBar) + +// *** Incoming data processing + +// Handle case where data is immediately available +cont() + +// Handle case where data may become available in the future +window.proxy = new Proxy(jsonpData, { + get(obj, prop) { + return value => { + obj[prop] = value + cont() + } + } +}) + +// *** Data upload and download async function cont() { - if (!(wikiPage && siteinfo)) return + if (jsonpData.wikipage?.error) return error(jsonpData.wikipage) + if (jsonpData.siteinfo?.error) return error(jsonpData.siteinfo) + if (!(jsonpData.wikipage && jsonpData.siteinfo)) return const xhr = new XMLHttpRequest(); @@ -46,14 +65,34 @@ async function cont() { document.head.appendChild(imported) } } + const redirectTo = document.querySelector("#content .redirectMsg a") + if (redirectTo) { + redirectTo.click() + } }) xhr.open("POST", "/api/render/wiki") xhr.responseType = "document" xhr.send(JSON.stringify({ - data: wikiPage, - siteinfo, - wikiname, - path + data: jsonpData.wikipage, + siteinfo: jsonpData.siteinfo, + wikiname: BWData.wikiname, + path: BWData.path })); } + +function error(data) { + const eContent = document.getElementById("content") + while (eContent.childNodes[0] !== undefined) eContent.childNodes[0].remove() // clear out loading indicators + document.title = `Error | BreezeWiki` + render(html` +${data.error.code === "missingtitle" +? html`

This page doesn't exist on Fandom.

` +: html` +

BreezeWiki wasn't able to load this page.

+

${data.error.code}: ${data.error.info}

+` +} +

Return to the homepage?

+`, eContent) +}