dsh-tiddlywiki 0.26.6 → 0.26.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/lib/client.js +27 -27
- package/lib/index.js +44 -3
- package/lib/index.js.map +1 -1
- package/package.json +2 -2
- package/src/client/endpoints.ts +27 -0
- package/src/client/note-widget.ts +8 -5
- package/src/client/status-cache.ts +7 -0
- package/src/client/tw-frame.ts +20 -4
- package/src/host/http.ts +34 -1
- package/src/host/routes.ts +16 -3
package/lib/index.js
CHANGED
|
@@ -2574,10 +2574,40 @@ function rejectCrossSiteWrite(req, res, allowedMethods) {
|
|
|
2574
2574
|
}, 403);
|
|
2575
2575
|
return true;
|
|
2576
2576
|
}
|
|
2577
|
-
/**
|
|
2577
|
+
/**
|
|
2578
|
+
* Read-only route guard: GET/HEAD only, no side effects on any other method. */
|
|
2578
2579
|
function rejectNonRead(req, res) {
|
|
2579
2580
|
return rejectCrossSiteWrite(req, res, ["GET", "HEAD"]);
|
|
2580
2581
|
}
|
|
2582
|
+
/**
|
|
2583
|
+
* Absolute loopback base for a same-origin proxy path, from a request's `Host`
|
|
2584
|
+
* header (v0.26.7). Returns undefined when the header is unusable, in which
|
|
2585
|
+
* case the caller simply omits the absolute twin and clients keep using the
|
|
2586
|
+
* relative path.
|
|
2587
|
+
*
|
|
2588
|
+
* WHY THIS EXISTS: the DSH **desktop** app serves its renderer from the custom
|
|
2589
|
+
* `dsh-app:` scheme, and TiddlyWiki's own TiddlyWeb sync adaptor refuses to load
|
|
2590
|
+
* on a document whose protocol does not start with `http`
|
|
2591
|
+
* (`plugins/tiddlywiki/tiddlyweb/tiddlywebadaptor.js`:
|
|
2592
|
+
* `if($tw.browser && document.location.protocol.substr(0,4) === "http")`).
|
|
2593
|
+
* Embedded from `dsh-app://app/…` the wiki therefore had NO sync adaptor:
|
|
2594
|
+
* `$:/status/IsReadOnly` was never written, TW's read-only stylesheet (which
|
|
2595
|
+
* treats a MISSING status as read-only) hid 添加条目 / 日志 / 导入 / 管理器 /
|
|
2596
|
+
* 编辑 …, and the saver fell back to local-only dirty tracking — an edit made
|
|
2597
|
+
* there could not be saved either. The client falls back to this absolute URL
|
|
2598
|
+
* only while its own document is not on http(s) (see `resolveTwUrl` in
|
|
2599
|
+
* `src/client/endpoints.ts`), so http(s) embedders — loopback, LAN, Tailscale,
|
|
2600
|
+
* domain, HTTPS — are never moved off their own origin.
|
|
2601
|
+
*
|
|
2602
|
+
* `http` is deliberate rather than `x-forwarded-proto`: the desktop app's host
|
|
2603
|
+
* always listens on plain HTTP loopback, and only a renderer able to reach it
|
|
2604
|
+
* ever reads this value.
|
|
2605
|
+
*/
|
|
2606
|
+
function absoluteHostBase(hostHeader, proxyPath) {
|
|
2607
|
+
const host = typeof hostHeader === "string" ? hostHeader.trim() : Array.isArray(hostHeader) ? String(hostHeader[0] ?? "").trim() : "";
|
|
2608
|
+
if (!/^[A-Za-z0-9.\-[\]:]+$/.test(host)) return void 0;
|
|
2609
|
+
return `http://${host}${proxyPath}`;
|
|
2610
|
+
}
|
|
2581
2611
|
//#endregion
|
|
2582
2612
|
//#region src/host/sanitize.ts
|
|
2583
2613
|
/**
|
|
@@ -6679,6 +6709,14 @@ function registerRoutes(ctx, deps) {
|
|
|
6679
6709
|
* tags, it cannot know the text is a secret.
|
|
6680
6710
|
*/
|
|
6681
6711
|
const referencesBlockedTitle = (value) => value !== void 0 && BLOCKED_PROXY_TITLE_PREFIXES.some((prefix) => value.includes(prefix));
|
|
6712
|
+
/**
|
|
6713
|
+
* Absolute twin of `twProxy` for embedders whose own document is not on
|
|
6714
|
+
* http(s) — the DSH desktop app's `dsh-app:` renderer (v0.26.7). See
|
|
6715
|
+
* `absoluteHostBase()` in http.ts for the full why; clients only consult it
|
|
6716
|
+
* while their own page is not http(s), so nothing changes for http(s)
|
|
6717
|
+
* deployments.
|
|
6718
|
+
*/
|
|
6719
|
+
const twProxyAbsoluteBase = (req) => absoluteHostBase(req.headers.host, TW_PROXY_PATH);
|
|
6682
6720
|
const handleStatus = async (req, res) => {
|
|
6683
6721
|
if (rejectNonRead(req, res)) return;
|
|
6684
6722
|
const view = deps.server.status();
|
|
@@ -6688,6 +6726,7 @@ function registerRoutes(ctx, deps) {
|
|
|
6688
6726
|
...view,
|
|
6689
6727
|
logs: redactLogLines(view.logs),
|
|
6690
6728
|
twProxy: TW_PROXY_PATH,
|
|
6729
|
+
twProxyAbsolute: twProxyAbsoluteBase(req),
|
|
6691
6730
|
git: gitSummary,
|
|
6692
6731
|
note: { tag: deps.noteDefaults().tag },
|
|
6693
6732
|
ui: deps.uiDefaults()
|
|
@@ -6765,7 +6804,8 @@ function registerRoutes(ctx, deps) {
|
|
|
6765
6804
|
json(res, {
|
|
6766
6805
|
ok: true,
|
|
6767
6806
|
...await pendingSummary,
|
|
6768
|
-
twUrl: TW_PROXY_PATH
|
|
6807
|
+
twUrl: TW_PROXY_PATH,
|
|
6808
|
+
twUrlAbsolute: twProxyAbsoluteBase(req)
|
|
6769
6809
|
});
|
|
6770
6810
|
} catch (err) {
|
|
6771
6811
|
json(res, {
|
|
@@ -7186,7 +7226,8 @@ function registerRoutes(ctx, deps) {
|
|
|
7186
7226
|
json(res, {
|
|
7187
7227
|
ok: true,
|
|
7188
7228
|
...result,
|
|
7189
|
-
twUrl: TW_PROXY_PATH
|
|
7229
|
+
twUrl: TW_PROXY_PATH,
|
|
7230
|
+
twUrlAbsolute: twProxyAbsoluteBase(req)
|
|
7190
7231
|
});
|
|
7191
7232
|
} catch (err) {
|
|
7192
7233
|
if (err instanceof WriteConflictError) {
|