From 9693281cb4fc035c87d1f3cf3e4c6f77d8eb0205 Mon Sep 17 00:00:00 2001 From: telumire Date: Tue, 19 Nov 2024 10:53:42 +0000 Subject: [PATCH 01/11] add trimming to the "UploadApp" tiddler --- plugins/tiddlypwa/upload-app-form.tid | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/plugins/tiddlypwa/upload-app-form.tid b/plugins/tiddlypwa/upload-app-form.tid index 956e30e..5cc9d3d 100644 --- a/plugins/tiddlypwa/upload-app-form.tid +++ b/plugins/tiddlypwa/upload-app-form.tid @@ -1,10 +1,20 @@ title: $:/plugins/valpackett/tiddlypwa/upload-app-form +\procedure input(tiddler,id,tag:input,default) +<$tiddler tiddler=<> > +<$edit-text inputActions=<> id=<> tag=<> default=<> /> + +\end + +\procedure inputActions() +<$action-setfield text={{{ [trim[]] }}} /> +\end +
|tc-table-no-border tc-max-width tc-first-col-min-width|k -| URL|<$edit-text id="tpwa-endpoint-url" tiddler="$:/temp/TiddlyPWAServerURL" tag="input" default="https://" /> | -| Token|<$edit-text tiddler="$:/temp/TiddlyPWAServerToken" tag="input" default="" /> | +| URL|<> | +| Token|<> | | |<$button><$action-sendmessage $message="tiddlypwa-upload-app-wiki" publishFilter={{$:/plugins/valpackett/tiddlypwa/app-filter}} uploadUrl={{$:/temp/TiddlyPWAServerURL}} uploadToken={{$:/temp/TiddlyPWAServerToken}} />Upload | -
+ \ No newline at end of file From 1541ba558912c7a86ba07ca746f5ff9effa1016b Mon Sep 17 00:00:00 2001 From: Val Packett Date: Wed, 13 Nov 2024 16:34:33 -0300 Subject: [PATCH 02/11] Move the site to bnnuy --- .woodpecker.yml | 44 +++++++++++++++++++++++++++++++++++++------- bunny.sh | 8 ++++++++ netlify.toml | 18 ------------------ 3 files changed, 45 insertions(+), 25 deletions(-) create mode 100755 bunny.sh delete mode 100644 netlify.toml diff --git a/.woodpecker.yml b/.woodpecker.yml index ec4bd57..32086a2 100644 --- a/.woodpecker.yml +++ b/.woodpecker.yml @@ -1,9 +1,39 @@ +when: + - event: push + steps: - test: - image: denoland/deno:alpine-1.45.4 + - name: test + image: denoland/deno:alpine + pull: true commands: - - deno test - - DENO_FUTURE=1 deno test - - echo uwu | DENO_FUTURE=1 deno run server/hash-admin-password.ts - - deno fmt --check - - DENO_FUTURE=1 deno run --allow-env --allow-read --allow-write=output npm:tiddlywiki@5.3.5 --build + - deno test server + - echo uwu | deno run server/hash-admin-password.ts + - name: fmt + image: denoland/deno:alpine + commands: + - deno fmt --check --ignore="**/*.css" plugins server + - name: fetch_theme + image: alpine/curl + when: + - event: push + branch: release + commands: + - mkdir notebook + - curl -L https://github.com/valpackett/Notebook/archive/e2c61ccd6e9db5cfcbc77e54eccc8b5961da5831.tar.gz | tar -xvzf - -C notebook --strip-components=1 + - name: build + image: denoland/deno:alpine + environment: + TIDDLYWIKI_THEME_PATH: notebook/themes + TIDDLYWIKI_PLUGIN_PATH: notebook/plugins + commands: + - deno run --allow-env --allow-read --allow-write=output npm:tiddlywiki@5.3.5 --build + - name: push + image: alpine/curl + when: + - event: push + branch: release + secrets: + - BUNNY_BUCKET + - BUNNY_KEY + commands: + - sh bunny.sh diff --git a/bunny.sh b/bunny.sh new file mode 100755 index 0000000..f5df6e0 --- /dev/null +++ b/bunny.sh @@ -0,0 +1,8 @@ +#!/bin/sh +set -e +cd output +find * -type f -exec curl --fail --request PUT \ + --url https://storage.bunnycdn.com/$BUNNY_BUCKET/{} \ + --header "AccessKey: $BUNNY_KEY" \ + --header "Content-Type: application/octet-stream" \ + --data-binary @{} \; diff --git a/netlify.toml b/netlify.toml deleted file mode 100644 index bed23b7..0000000 --- a/netlify.toml +++ /dev/null @@ -1,18 +0,0 @@ -[build] -publish = "output" -command = """ - mkdir notebook; curl -L https://github.com/valpackett/Notebook/archive/e2c61ccd6e9db5cfcbc77e54eccc8b5961da5831.tar.gz | tar -xvzf - -C notebook --strip-components=1 && - TIDDLYWIKI_THEME_PATH=notebook/themes TIDDLYWIKI_PLUGIN_PATH=notebook/plugins npx tiddlywiki@5.3.5 --build -""" - -[[headers]] -for = "/*" -[headers.values] -x-content-type-options = "nosniff" -x-frame-options = "SAMEORIGIN" -referrer-policy = "no-referrer-when-downgrade" - -[[redirects]] -from = "/w/:name/:file" -to = "/app/:file" -status = 200 From 71509921d6d06cb27cb2d9a4d03add595f7f3f3e Mon Sep 17 00:00:00 2001 From: Val Packett Date: Wed, 26 Feb 2025 18:07:25 -0300 Subject: [PATCH 03/11] Update woodpecker config for 3.0.0 --- .woodpecker.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.woodpecker.yml b/.woodpecker.yml index 32086a2..f2e9a98 100644 --- a/.woodpecker.yml +++ b/.woodpecker.yml @@ -32,8 +32,10 @@ steps: when: - event: push branch: release - secrets: - - BUNNY_BUCKET - - BUNNY_KEY + environment: + BUNNY_BUCKET: + from_secret: BUNNY_BUCKET + BUNNY_KEY: + from_secret: BUNNY_KEY commands: - sh bunny.sh From ef786f611aef3fcf7e15298f3713e5e676f0b93e Mon Sep 17 00:00:00 2001 From: Val Packett Date: Wed, 26 Feb 2025 18:07:25 -0300 Subject: [PATCH 04/11] Docs: systemd unit and various clarifications --- tiddlers/AfterServerHosting.tid | 4 +- tiddlers/ServerHostingDIY.tid | 66 +++++++++++++++++++++++++++++++-- 2 files changed, 65 insertions(+), 5 deletions(-) diff --git a/tiddlers/AfterServerHosting.tid b/tiddlers/AfterServerHosting.tid index 8000137..cbce09f 100644 --- a/tiddlers/AfterServerHosting.tid +++ b/tiddlers/AfterServerHosting.tid @@ -6,7 +6,7 @@ tags: [[TiddlyPWA Docs]] Opening the `/` home page of the hosted sync server will let you access the admin console with the admin password. There, you can create "wikis", i.e. storage slots that can store synchronized tiddlers ''and'' an app wiki, i.e. the TiddlyWiki HTML file with plugins and themes in it. -Hosting the app wiki on the sync server is not obligatory, but ''highly recommend'' because it simplifies setup on multiple devices and allows easy plugin/theme installation. +Hosting the app wiki on the sync server is not obligatory, but ''highly recommended'' because it simplifies setup on multiple devices and allows easy plugin/theme installation. Once you have created a storage slot, you get a token that you can use for syncing the tiddlers and uploading the app wiki. @@ -16,4 +16,4 @@ Once you have created a storage slot, you get a token that you can use for synci Upon uploading the app wiki, you'll see the URL for the hosted app wiki. Now you should bookmark that URL and use it to access the wiki. It will also be accessible from the admin panel, by clicking the app wiki size. -Enjoy! \ No newline at end of file +Enjoy! diff --git a/tiddlers/ServerHostingDIY.tid b/tiddlers/ServerHostingDIY.tid index 6f3780c..a7ec9fb 100644 --- a/tiddlers/ServerHostingDIY.tid +++ b/tiddlers/ServerHostingDIY.tid @@ -26,12 +26,16 @@ or use a unix domain socket passing the path as `--socket` (you'll need to both You can pass the `--dotenv` flag to make the app read variables from a `.env` file (which is mostly used in development with the included file that contains a hash of the `test` password.) +You can customize the location of the Deno module cache using the `DENO_DIR` environment variable. + You really need to have TLS (HTTPS) working, so run this behind a reverse proxy like [[Caddy|https://caddyserver.com/]], [[H2O|https://h2o.examp1e.net/]] or [[Nginx|https://nginx.org/en/]]. Caddy is famous for fully integrated [[automatic HTTPS|https://caddyserver.com/docs/automatic-https]] support, supporting [[Let's Encrypt|https://letsencrypt.org/]] on the public web as well working with [[Tailscale|https://tailscale.com/]]'s HTTPS support. -(Also [[caddy-tailscale|https://github.com/tailscale/caddy-tailscale]] exists for hosting a bunch of as separate Tailscale hosts!) +(Though [[Tailscale Serve|https://tailscale.com/kb/1312/serve]] can do basic TLS reverse proxying inside of tailscaled itself; also [[caddy-tailscale|https://github.com/tailscale/caddy-tailscale]] exists for hosting a bunch of as separate Tailscale hosts!) When running behind a reverse proxy that rewrites paths, you can customize the base path used for wiki using the `--basepath` flag. It should match the respective Caddy rewrite directive / H2O path / Nginx location, without a trailing backslash. By default, the server assumes no path rewriting takes place. +If you're running Linux with systemd, see below for an example unit file. + {{AfterServerHosting}} !! Updating @@ -45,8 +49,11 @@ To refresh the cached version of the server scripts, you can use this command: Thanks to Deno providing [[sandboxing|https://docs.deno.com/runtime/manual/basics/permissions]] by default, the server process does not get permission to access anything other than what was specified in the `--allow-*` flags. You can be confident that unless there's a horrible bug in the Deno runtime, the code is unable to touch anything outside of the database directory, nor is it able to contact external network services, nor launch processes. -If you're paranoid enough to audit all the server code, you can use the [[deno info|https://docs.deno.com/runtime/manual/tools/dependency_inspector]] dependency inspector and/or [[deno vendor|https://docs.deno.com/runtime/manual/tools/vendor]] which conveniently places everything in a friendly directory tree instead of the cache, making it a lot more convenient to review. -You can then add `--no-remote --import-map path/to/vendor/import_map.json` flags to the `deno run` invocation (and you can still refer to the URL!) to strongly guarantee that Deno will only run code from the directory you reviewed. +If you're running it on Linux with systemd, systemd options can (and should) be used to enforce an additional layer of sandboxing. +The example unit file below uses them. + +If you're paranoid enough to audit all the server code, you can use the [[deno info|https://docs.deno.com/runtime/manual/tools/dependency_inspector]] dependency inspector. +You can also check out Deno's `--vendor` and `--cached-only` flags. !! Single-Binary Deployment @@ -64,3 +71,56 @@ deno compile -o tiddlypwa-sync-server \ ADMIN_PASSWORD_HASH=Zn…PQ ADMIN_PASSWORD_SALT=q6…0o DB_PATH=/var/db/tiddly/pwa.db ./tiddlypwa-sync-server ``` + +!! Example systemd unit file + +``` +[Unit] +Description=TiddlyPWA sync server +Documentation=https://tiddly.packett.cool/ +Wants=network-online.target +After=network-online.target + +[Service] +Type=simple +User=tiddlypwa +Group=tiddlypwa +DynamicUser=yes +StateDirectory=tiddlypwa +CacheDirectory=tiddlypwa +NoNewPrivileges=yes +PrivateTmp=yes +PrivateUsers=yes +PrivateDevices=yes +ProtectSystem=strict +ProtectHome=yes +ProtectHostname=yes +ProtectControlGroups=yes +ProtectKernelModules=yes +ProtectKernelLogs=yes +ProtectKernelTunables=yes +ProtectClock=yes +ProtectProc=noaccess +ProcSubset=pid +RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 +RestrictNamespaces=yes +RestrictRealtime=yes +LockPersonality=yes +SystemCallFilter=@system-service +SystemCallErrorNumber=EPERM +SystemCallArchitectures=native +CapabilityBoundingSet= +EnvironmentFile=/etc/tiddlypwa.env +Environment=DB_PATH=/var/lib/tiddlypwa/pwa.db +Environment=DENO_DIR=/var/cache/tiddlypwa/deno +ExecStart=/usr/bin/deno --unstable-broadcast-channel --allow-env \ + --allow-read=/var/lib/tiddlypwa --allow-write=/var/lib/tiddlypwa \ + --allow-net=:7770 \ + https://codeberg.org/valpackett/tiddlypwa/raw/branch/release/server/run.ts --port 7770 +Restart=on-failure + +[Install] +WantedBy=multi-user.target +``` + +Put the above into `/etc/systemd/system/tiddlypwa.service` and write the admin hash/salt variables to `/etc/tiddlypwa.env`. From 05d24a9efda634845a614b71ac39cda69069874a Mon Sep 17 00:00:00 2001 From: Val Packett Date: Wed, 2 Apr 2025 20:11:06 -0300 Subject: [PATCH 05/11] Server: fix base64 ArrayBuffer typechecking with new Deno --- server/app.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/server/app.ts b/server/app.ts index 3c7c01a..198d916 100644 --- a/server/app.ts +++ b/server/app.ts @@ -64,7 +64,7 @@ function supportsEncoding(headers: Headers, enc: string): boolean { function processEtag(etag: Uint8Array, headers: Headers): [boolean, string] { const supportsBrotli = supportsEncoding(headers, 'br'); - return [supportsBrotli, '"' + base64.encode(etag) + (supportsBrotli ? '-b' : '-x') + '"']; + return [supportsBrotli, '"' + base64.encode(etag.buffer as ArrayBuffer) + (supportsBrotli ? '-b' : '-x') + '"']; } function notifyMonitors(token: string, browserToken: string) { @@ -132,11 +132,11 @@ export class TiddlyPWASyncApp { // console.log('ServHas', base64nourl.encode(thash as Uint8Array), mtime, modsince, mtime < modsince); ctrl.enqueue( (firstWritten ? '\n,' : '\n') + JSON.stringify({ - thash: thash ? base64nourl.encode(thash as Uint8Array) : null, - iv: iv ? base64nourl.encode(iv as Uint8Array) : null, - ct: ct ? base64nourl.encode(ct as Uint8Array) : null, - sbiv: sbiv ? base64nourl.encode(sbiv as Uint8Array) : null, - sbct: sbct ? base64nourl.encode(sbct as Uint8Array) : null, + thash: thash ? base64nourl.encode(thash.buffer as ArrayBuffer) : null, + iv: iv ? base64nourl.encode(iv.buffer as ArrayBuffer) : null, + ct: ct ? base64nourl.encode(ct.buffer as ArrayBuffer) : null, + sbiv: sbiv ? base64nourl.encode(sbiv.buffer as ArrayBuffer) : null, + sbct: sbct ? base64nourl.encode(sbct.buffer as ArrayBuffer) : null, mtime, deleted, }), @@ -174,7 +174,7 @@ export class TiddlyPWASyncApp { if (note !== undefined && typeof note !== 'string') { return Response.json({ error: 'EPROTO' }, { headers: respHdrs, status: 400 }); } - const token = base64.encode(crypto.getRandomValues(new Uint8Array(32))); + const token = base64.encode(crypto.getRandomValues(new Uint8Array(32)).buffer); this.db.createWiki(token, note); return Response.json({ token }, { headers: respHdrs, status: 201 }); } From 29613963104d2a27e5d7d774a7a4750b19ba30b1 Mon Sep 17 00:00:00 2001 From: Val Packett Date: Wed, 2 Apr 2025 18:30:17 -0300 Subject: [PATCH 06/11] Switch to Forgejo Actions --- .forgejo/workflows/check.yaml | 22 ++++++++++++++++++ .forgejo/workflows/upload.yaml | 22 ++++++++++++++++++ .woodpecker.yml | 41 ---------------------------------- 3 files changed, 44 insertions(+), 41 deletions(-) create mode 100644 .forgejo/workflows/check.yaml create mode 100644 .forgejo/workflows/upload.yaml delete mode 100644 .woodpecker.yml diff --git a/.forgejo/workflows/check.yaml b/.forgejo/workflows/check.yaml new file mode 100644 index 0000000..7cf9883 --- /dev/null +++ b/.forgejo/workflows/check.yaml @@ -0,0 +1,22 @@ +--- +on: + push: + branches: [trunk] + pull_request: + types: [opened, synchronize, reopened] +jobs: + test: + runs-on: val-arm64 + steps: + - name: Checkout + uses: https://code.forgejo.org/actions/checkout@v4 + - name: Get Deno + run: curl -fsSL https://deno.land/install.sh | sh + - name: Run server tests + run: /root/.deno/bin/deno test server + - name: Try hash-admin-password + run: echo uwu | /root/.deno/bin/deno run server/hash-admin-password.ts + - name: Check client build + run: /root/.deno/bin/deno run --allow-env --allow-read --allow-write=output npm:tiddlywiki@5.3.5 --build + - name: Check formatting + run: /root/.deno/bin/deno fmt --check --ignore="**/*.css" plugins server diff --git a/.forgejo/workflows/upload.yaml b/.forgejo/workflows/upload.yaml new file mode 100644 index 0000000..680fcbb --- /dev/null +++ b/.forgejo/workflows/upload.yaml @@ -0,0 +1,22 @@ +--- +on: + push: + branches: [release] +jobs: + test: + runs-on: val-arm64 + steps: + - name: Checkout + uses: https://code.forgejo.org/actions/checkout@v4 + - name: Fetch theme + run: mkdir notebook && curl -L https://github.com/valpackett/Notebook/archive/e2c61ccd6e9db5cfcbc77e54eccc8b5961da5831.tar.gz | tar -xvzf - -C notebook --strip-components=1 + - name: Build client + run: npx tiddlywiki@5.3.5 --build + env: + TIDDLYWIKI_THEME_PATH: notebook/themes + TIDDLYWIKI_PLUGIN_PATH: notebook/plugins + - name: Upload result + run: sh bunny.sh + env: + BUNNY_BUCKET: ${{ secrets.BUNNY_BUCKET }} + BUNNY_KEY: ${{ secrets.BUNNY_KEY }} diff --git a/.woodpecker.yml b/.woodpecker.yml deleted file mode 100644 index f2e9a98..0000000 --- a/.woodpecker.yml +++ /dev/null @@ -1,41 +0,0 @@ -when: - - event: push - -steps: - - name: test - image: denoland/deno:alpine - pull: true - commands: - - deno test server - - echo uwu | deno run server/hash-admin-password.ts - - name: fmt - image: denoland/deno:alpine - commands: - - deno fmt --check --ignore="**/*.css" plugins server - - name: fetch_theme - image: alpine/curl - when: - - event: push - branch: release - commands: - - mkdir notebook - - curl -L https://github.com/valpackett/Notebook/archive/e2c61ccd6e9db5cfcbc77e54eccc8b5961da5831.tar.gz | tar -xvzf - -C notebook --strip-components=1 - - name: build - image: denoland/deno:alpine - environment: - TIDDLYWIKI_THEME_PATH: notebook/themes - TIDDLYWIKI_PLUGIN_PATH: notebook/plugins - commands: - - deno run --allow-env --allow-read --allow-write=output npm:tiddlywiki@5.3.5 --build - - name: push - image: alpine/curl - when: - - event: push - branch: release - environment: - BUNNY_BUCKET: - from_secret: BUNNY_BUCKET - BUNNY_KEY: - from_secret: BUNNY_KEY - commands: - - sh bunny.sh From 8c55b22aa710f869dc83514004c40fec52f4f669 Mon Sep 17 00:00:00 2001 From: Val Packett Date: Wed, 2 Apr 2025 20:34:12 -0300 Subject: [PATCH 07/11] Remove outdated readme badges --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 3f6c6f9..cb3d3eb 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,3 @@ -[![CI status](https://ci.codeberg.org/api/badges/valpackett/tiddlypwa/status.svg)](https://ci.codeberg.org/valpackett/tiddlypwa) -[![Netlify Status](https://api.netlify.com/api/v1/badges/2c2cbd41-1ced-4f78-acc7-83889f95bcc2/deploy-status)](https://app.netlify.com/sites/tiddly-packett-cool/deploys) [![Support me on Patreon](https://img.shields.io/badge/dynamic/json?logo=patreon&color=%23e85b46&label=support%20me%20on%20patreon&query=data.attributes.patron_count&suffix=%20patrons&url=https%3A%2F%2Fwww.patreon.com%2Fapi%2Fcampaigns%2F9395291)](https://www.patreon.com/valpackett) # TiddlyPWA From 7ff63eb69670d20e2bb6e63b55ef331c8b1c9a6d Mon Sep 17 00:00:00 2001 From: sunlaud Date: Tue, 17 Jun 2025 01:07:08 +0300 Subject: [PATCH 08/11] Bugfix: login dialog is obscured by side panel Reproduces when * small screens (e.g. mobile) * Notebook theme installed * app wiki is stored with side panel opened --- plugins/tiddlypwa/bootstrap.js | 2 +- plugins/tiddlypwa/notif-refresh.tid | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/tiddlypwa/bootstrap.js b/plugins/tiddlypwa/bootstrap.js index 0bc9df8..2d1bccd 100644 --- a/plugins/tiddlypwa/bootstrap.js +++ b/plugins/tiddlypwa/bootstrap.js @@ -15,7 +15,7 @@ Formatted with `deno fmt`. const dm = $tw.utils.domMaker; module.exports.BootstrapModal = class { - wrapper = dm('div', { class: 'tc-modal-wrapper', style: { 'z-index': 1500 } }); // below alerts, above hide-sidebar-btn + wrapper = dm('div', { class: 'tc-modal-wrapper', style: { 'z-index': 4000 } }); // below alerts, above hide-sidebar-btn and others (e.g. side panel in Notebook theme has z-index=3000) constructor() { $tw.utils.addClass(document.body, 'tc-modal-prevent-scroll'); this.wrapper.appendChild(dm('div', { class: 'tc-modal-backdrop' })); diff --git a/plugins/tiddlypwa/notif-refresh.tid b/plugins/tiddlypwa/notif-refresh.tid index b129b9f..de6d0e5 100644 --- a/plugins/tiddlypwa/notif-refresh.tid +++ b/plugins/tiddlypwa/notif-refresh.tid @@ -3,7 +3,7 @@ tags: $:/tags/PageTemplate <$reveal type="nomatch" state="$:/temp/HideUpdate" text="yes"> <$reveal type="match" state="$:/status/TiddlyPWAUpdateAvailable" text="yes"> -