@tiddlywiki/mws 0.0.21 → 0.1.1
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 +42 -9
- package/dist/metafile-esm.json +1 -0
- package/dist/mws.d.ts +1 -0
- package/dist/mws.js +34710 -0
- package/dist/mws.js.map +1 -0
- package/editions/mws-docs/tiddlers/$__StoryList.tid +1 -2
- package/editions/mws-docs/tiddlers/2025-02-18 - User Management.md.meta +2 -2
- package/editions/mws-docs/tiddlers/2025-04-14 - client plugins /342/234/224/357/270/217.md" +31 -0
- package/editions/mws-docs/tiddlers/2025-04-14 - client plugins /342/234/224/357/270/217.md.meta" +5 -0
- package/editions/mws-docs/tiddlers/{2025-05-04.md → 2025-05-04 - event hooks /342/234/224/357/270/217.md" } +7 -1
- package/editions/mws-docs/tiddlers/2025-05-04 - event hooks /342/234/224/357/270/217.md.meta" +5 -0
- package/editions/mws-docs/tiddlers/{2025-05-06.md → 2025-05-06 - syncer design.md } +0 -4
- package/editions/mws-docs/tiddlers/2025-05-06 - syncer design.md.meta +5 -0
- package/editions/mws-docs/tiddlers/Allowed Methods.tid +8 -0
- package/editions/mws-docs/tiddlers/Application Access & Security.md +14 -84
- package/editions/mws-docs/tiddlers/Application Access & Security.md.meta +1 -1
- package/editions/mws-docs/tiddlers/Body Format.md +19 -0
- package/editions/mws-docs/tiddlers/Body Format.md.meta +4 -0
- package/editions/mws-docs/tiddlers/Checklists and Features.md +0 -3
- package/editions/mws-docs/tiddlers/Checklists and Features.md.meta +1 -1
- package/editions/mws-docs/tiddlers/Client Plugins.md +17 -0
- package/editions/mws-docs/tiddlers/Client Plugins.md.meta +5 -0
- package/editions/mws-docs/tiddlers/HTTP API.md +4 -3
- package/editions/mws-docs/tiddlers/HTTP API.md.meta +1 -1
- package/editions/mws-docs/tiddlers/HelloThere.tid +2 -2
- package/editions/mws-docs/tiddlers/Installation.tid +2 -3
- package/editions/mws-docs/tiddlers/MWS Architecture.tid +6 -1
- package/editions/mws-docs/tiddlers/Multi-user Trust.md +12 -0
- package/editions/mws-docs/tiddlers/Multi-user Trust.md.meta +5 -0
- package/editions/mws-docs/tiddlers/Notes.tid +5 -3
- package/editions/mws-docs/tiddlers/Oracle Attacks.md +29 -0
- package/editions/mws-docs/tiddlers/Oracle Attacks.md.meta +5 -0
- package/editions/mws-docs/tiddlers/Reference.md +1 -0
- package/editions/mws-docs/tiddlers/Reference.md.meta +1 -1
- package/editions/mws-docs/tiddlers/Request Handling.md +53 -0
- package/editions/mws-docs/tiddlers/Request Handling.md.meta +5 -0
- package/editions/mws-docs/tiddlers/Roadmap.tid +7 -0
- package/editions/mws-docs/tiddlers/Route Definers.md +206 -0
- package/editions/mws-docs/tiddlers/Route Definers.md.meta +5 -0
- package/editions/mws-docs/tiddlers/Security.md +75 -0
- package/editions/mws-docs/tiddlers/Security.md.meta +5 -0
- package/editions/mws-docs/tiddlers/Server Plugins.md +7 -0
- package/editions/mws-docs/tiddlers/Server Plugins.md.meta +5 -0
- package/editions/mws-docs/tiddlers/Startup Cache.md +28 -0
- package/editions/mws-docs/tiddlers/Startup Cache.md.meta +5 -0
- package/editions/mws-docs/tiddlers/TiddlerFields.md +5 -0
- package/editions/mws-docs/tiddlers/TiddlerFields.md.meta +4 -0
- package/editions/mws-docs/tiddlers/Usage.tid +2 -2
- package/editions/mws-docs/tiddlers/system/$__mws_cssvar-macro.tid +10 -0
- package/editions/mws-docs/tiddlers/system/$__palettes_MUI +143 -0
- package/editions/mws-docs/tiddlers/system/$__palettes_MUI.meta +7 -0
- package/editions/mws-docs/tiddlers/system/$__palettes_MUI_styles.css +567 -0
- package/editions/mws-docs/tiddlers/system/$__palettes_MUI_styles.css.meta +6 -0
- package/editions/mws-docs/tiddlers/system/$__theme.tid +6 -0
- package/editions/mws-docs/tiddlers/system/SplashScreen.tid +21 -0
- package/editions/mws-docs/tiddlers/system/StaticBanner.tid +1 -1
- package/editions/mws-docs/tiddlers/system/Styles.tid +13 -0
- package/editions/mws-docs/tiddlers/system/palette.tid +4 -1
- package/editions/mws-docs/tiddlers/system/sidebarlayout.tid +4 -1
- package/editions/mws-docs/tiddlers/x-mws-tiddler.md +35 -0
- package/editions/mws-docs/tiddlers/x-mws-tiddler.md.meta +5 -0
- package/mws.run.mjs +30 -0
- package/package.json +47 -36
- package/plugins/client/package-lock.json +46 -83
- package/plugins/client/package.json +1 -6
- package/plugins/client/plugin.info +2 -2
- package/plugins/client/src/fflate.d.ts +1501 -0
- package/plugins/client/src/multiwikiclientadaptor.ts +768 -317
- package/plugins/client/src/mws.d.ts +4 -0
- package/plugins/client/src/types.d.ts +3928 -0
- package/plugins/client/tiddlers/en-US.multids +3 -0
- package/plugins/client/tiddlers/status/SaveWikiButtonTemplate.tid +3 -0
- package/plugins/client/tiddlers/status/icon-cloud.tid +4 -0
- package/plugins/client/tiddlers/status/info-segment.tid +8 -0
- package/plugins/client/tiddlers/status/readonly-styles.tid +27 -0
- package/plugins/client/tiddlers/status/save-offline.tid +7 -0
- package/plugins/client/tiddlers/status/save-wiki-button.tid +26 -0
- package/plugins/client/tiddlers/status/styles.tid +44 -0
- package/plugins/client/tiddlers/status/syncer-actions-copy-logs.tid +6 -0
- package/plugins/client/tiddlers/status/syncer-actions-login-status.tid +9 -0
- package/plugins/client/tiddlers/status/syncer-actions-login.tid +8 -0
- package/plugins/client/tiddlers/status/syncer-actions-logout.tid +8 -0
- package/plugins/client/tiddlers/status/syncer-actions-refresh.tid +9 -0
- package/plugins/client/tiddlers/status/syncer-actions-save-snapshot.tid +9 -0
- package/plugins/client/tiddlers/status/tags-syncerdropdown.tid +2 -0
- package/plugins/client/tiddlers/syncer/multiwikiclientadaptor.js +640 -0
- package/plugins/client/tiddlers/syncer/syncer.js +831 -0
- package/plugins/client/tsconfig.json +19 -16
- package/plugins/filter-ast-to-sql/example-run-series.ts +146 -0
- package/plugins/server/SplashScreen.tid +150 -0
- package/plugins/server/fflate.js +9 -0
- package/plugins/server/plugin.info +8 -0
- package/plugins/server/readme +1 -0
- package/plugins/server/url-polyfill.js +294 -0
- package/prisma/client/client.d.ts +1 -0
- package/prisma/client/client.js +3 -0
- package/prisma/client/default.d.ts +1 -0
- package/prisma/client/default.js +3 -0
- package/prisma/client/edge.d.ts +1 -0
- package/prisma/client/edge.js +297 -0
- package/prisma/client/index-browser.js +275 -0
- package/prisma/client/index.d.ts +17770 -0
- package/prisma/client/index.js +324 -0
- package/prisma/client/package.json +173 -0
- package/prisma/client/query_engine_bg.js +811 -0
- package/prisma/client/query_engine_bg.wasm +0 -0
- package/prisma/client/runtime/edge-esm.js +10000 -0
- package/prisma/client/runtime/edge.js +10036 -0
- package/prisma/client/runtime/index-browser.d.ts +370 -0
- package/prisma/client/runtime/index-browser.js +2300 -0
- package/prisma/client/runtime/library.d.ts +3681 -0
- package/prisma/client/runtime/library.js +10604 -0
- package/prisma/client/runtime/react-native.js +10629 -0
- package/prisma/client/runtime/wasm-compiler-edge.js +11238 -0
- package/prisma/client/runtime/wasm-engine-edge.js +7801 -0
- package/prisma/client/schema.prisma +156 -0
- package/prisma/client/wasm-edge-light-loader.mjs +4 -0
- package/prisma/client/wasm-worker-loader.mjs +4 -0
- package/prisma/client/wasm.d.ts +1 -0
- package/prisma/client/wasm.js +304 -0
- package/prisma/global.ts +53 -0
- package/prisma/migrations/{20250406213424_init → 20250606001949_init}/migration.sql +46 -48
- package/prisma/migrations/20250613000526_remove_group/migration.sql +22 -0
- package/prisma/migrations/20250620014502_settings/migration.sql +5 -0
- package/prisma/migrations/20250707205229_recipes/migration.sql +20 -0
- package/prisma/migrations/migration_lock.toml +1 -1
- package/prisma/notes.md +1 -2
- package/prisma/schema.prisma +52 -49
- package/prisma/test.sqlite +0 -0
- package/prisma/test.sqlite-journal +0 -0
- package/public/react-admin/android-chrome-192x192.png +0 -0
- package/public/react-admin/android-chrome-512x512.png +0 -0
- package/public/react-admin/apple-touch-icon.png +0 -0
- package/{react-user-mgmt/public/esm-QKDFEP3B.js → public/react-admin/esm-L4WLVWJN.js} +1 -1
- package/public/react-admin/esm-L4WLVWJN.js.map +7 -0
- package/public/react-admin/esm-QMNGI3LF.js +3 -0
- package/public/react-admin/favicon-16x16.png +0 -0
- package/public/react-admin/favicon-32x32.png +0 -0
- package/public/react-admin/favicon.ico +0 -0
- package/public/react-admin/index.html +36 -0
- package/public/react-admin/main.js +268 -0
- package/public/react-admin/main.js.map +7 -0
- package/public/react-admin/site.webmanifest +20 -0
- package/public/react-admin/stats.json +1 -0
- package/scripts.mjs +134 -25
- package/dist/server.d.ts +0 -945
- package/dist/server.js +0 -20775
- package/dist/server.js.map +0 -1
- package/editions/mws-docs/tiddlers/2025-04-03 - Phases of Development.md +0 -64
- package/editions/mws-docs/tiddlers/2025-04-03 - Phases of Development.md.meta +0 -5
- package/editions/mws-docs/tiddlers/2025-04-13 - Plugins.md +0 -18
- package/editions/mws-docs/tiddlers/2025-04-13 - Plugins.md.meta +0 -5
- package/editions/mws-docs/tiddlers/2025-05-04.md.meta +0 -5
- package/editions/mws-docs/tiddlers/2025-05-06.md.meta +0 -5
- package/editions/mws-docs/tiddlers/Moduler Design.md +0 -29
- package/editions/mws-docs/tiddlers/Moduler Design.md.meta +0 -5
- package/editions/mws-docs/tiddlers/Request Server.md +0 -20
- package/editions/mws-docs/tiddlers/Request Server.md.meta +0 -5
- package/editions/mws-docs/tiddlers/system/$__palettes_MUI-Dark +0 -173
- package/editions/mws-docs/tiddlers/system/$__palettes_MUI-Dark.meta +0 -6
- package/editions/mws-docs/tiddlers/system/$__palettes_MUI-Light +0 -172
- package/editions/mws-docs/tiddlers/system/$__palettes_MUI-Light.meta +0 -6
- package/plugins/client/tiddlers/config-tiddlers-filter.tid +0 -2
- package/plugins/client/tiddlers/config-use-server-sent-events.tid +0 -2
- package/plugins/client/tiddlers/info-segment.tid +0 -8
- package/plugins/client/tiddlers/multiwikiclientadaptor.js +0 -444
- package/prisma/migrations/20250407002306_disconnect_user_tables/migration.sql +0 -52
- package/prisma/old-db.sql +0 -144
- package/react-user-mgmt/README.md +0 -50
- package/react-user-mgmt/eslint.config.js +0 -28
- package/react-user-mgmt/package-lock.json +0 -2738
- package/react-user-mgmt/package.json +0 -31
- package/react-user-mgmt/public/index.html +0 -1
- package/react-user-mgmt/public/main.js +0 -295
- package/react-user-mgmt/public/main.js.map +0 -7
- package/react-user-mgmt/public/stats.json +0 -1
- package/react-user-mgmt/tsconfig.json +0 -40
- package/react-user-mgmt/types.d.ts +0 -2
- package/tiddlywiki-types/boot/boot.d.ts +0 -378
- package/tiddlywiki-types/boot/bootprefix.d.ts +0 -110
- package/tiddlywiki-types/core/modules/filters.d.ts +0 -107
- package/tiddlywiki-types/core/modules/tiddler.d.ts +0 -47
- package/tiddlywiki-types/core/modules/wiki-bulkops.d.ts +0 -36
- package/tiddlywiki-types/core/modules/wiki.d.ts +0 -208
- package/tiddlywiki-types/index.d.ts +0 -7
- package/tiddlywiki-types/package.json +0 -3
- /package/plugins/client/tiddlers/{sidebarsegment.tid → status/sidebarsegment.tid} +0 -0
- /package/plugins/client/tiddlers/{GettingStarted.tid → syncer/GettingStarted.tid} +0 -0
- /package/plugins/client/tiddlers/{config-incoming-updates-filter.tid → syncer/config-incoming-updates-filter.tid} +0 -0
- /package/plugins/client/tiddlers/{readme.tid → syncer/readme.tid} +0 -0
- /package/{react-user-mgmt/public → public/react-admin}/chunk-YALWN5OT.js +0 -0
- /package/{react-user-mgmt/public → public/react-admin}/chunk-YALWN5OT.js.map +0 -0
- /package/{react-user-mgmt/public/esm-QKDFEP3B.js.map → public/react-admin/esm-QMNGI3LF.js.map} +0 -0
- /package/{react-user-mgmt/public → public/react-admin}/favicon.png +0 -0
- /package/{react-user-mgmt/public → public/react-admin}/missing-favicon.png +0 -0
- /package/{react-user-mgmt/public → public/react-admin}/motovun-jack.jpg +0 -0
- /package/{react-user-mgmt/public → public/react-admin}/mws-icon.png +0 -0
- /package/{react-user-mgmt/public → public/react-admin}/stats.css +0 -0
- /package/{react-user-mgmt/public → public/react-admin}/stats.html +0 -0
- /package/{react-user-mgmt/public → public/react-admin}/stats.js +0 -0
- /package/{react-user-mgmt/public → public/react-admin}/stats.svg +0 -0
- /package/{react-user-mgmt/public → public/react-admin}/vite.svg +0 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
Currently we're adding recipe tiddlers into the wiki page dynamically, which is expected, but there are like six tiddlers that are being rendered statically, which doesn't really make sense. It also doesn't make sense that we're dumping some plugins into the database but rendering core from tiddlywiki, since this results in a version mismatch.
|
|
2
|
+
|
|
3
|
+
At the same time, we really don't want to be rendering plugins every time. They do need to be cached somewhere so they can be loaded quickly. I wonder if it would work to cache them in the wiki folder, per tiddlywiki version, so if you upgrade it would just create a new folder. The boot tiddlers would be cached in the folder as well. If we do it right, we wouldn't even have to parse the file, just read it onto the wire. We'd probably need an index file to keep everything straight. We could add plugins/themes/languages support to the wiki folder as well, which would also get cached in the same way. We could make a way for caching to be disabled, perhaps by adding a field to `plugin.info`.
|
|
4
|
+
|
|
5
|
+
It would be useful if the plugin syntax could specify NPM modules. We already have the `+` and `++` syntax. I'm not sure exactly how it'd work, but the NPM package would need to determine it's own path, which is fairly simple, and then export that so it can be imported via the standard import mechanism. Obviously the package would need to be installed, and it should probably be imported into the run file and then added as an absolute path to the list of imports. Actually, I guess that's already possible, so I just need to add the list of imports part of it.
|
|
6
|
+
|
|
7
|
+
----
|
|
8
|
+
|
|
9
|
+
### Add a tiddler cache folder and render the tiddlers on startup
|
|
10
|
+
|
|
11
|
+
- Store them either in-memory or in the file-system, depending on user preference.
|
|
12
|
+
- The core tiddler and boot tiddlers could be stored in memory regardless because they are always served.
|
|
13
|
+
- Would it save some memory to store them as a buffer?
|
|
14
|
+
- The stored content would be read directly onto the wire, optionally checking the hash.
|
|
15
|
+
|
|
16
|
+
### Add a plugin selector to the recipes form
|
|
17
|
+
|
|
18
|
+
- The loading order needs to be changeable.
|
|
19
|
+
- It would just be an array of titles, and possibly other describing fields.
|
|
20
|
+
|
|
21
|
+
### Add a plugin field to the recipes table
|
|
22
|
+
|
|
23
|
+
- Not sure if I need to create a plugins table but I probably just need a string array of plugin names. Titles tend to be authoritative in TiddlyWiki so the plugin title should be enough. Plugin titles which cannot be found would be somehow marked as not found, probably with a custom disabled plugin tiddler in the client and logging a warning in the server.
|
|
24
|
+
|
|
25
|
+
### What about SQL Filters?
|
|
26
|
+
|
|
27
|
+
- I don't know, but we would be caching plugins either way. Everything about it is handled differently, so no matter what, there is almost guaranteed to be a clear separation between the two kinds of bags anyway. We'll worry about that when we get there.
|
|
28
|
+
|
|
29
|
+
## Retrospective - 2025-06-24
|
|
30
|
+
|
|
31
|
+
I ended up caching it according to the file path. The tiddlywiki file path works fine for those plugins. Third-party plugins will need to declare their own folder name somehow. The files are compressed and stored on disk. The cache is built on startup. The cache stores a `json`, `js`, and `js.gz` version of each plugin.
|
|
@@ -10,4 +10,10 @@ I probably need a startup state object, which basically has the site config and
|
|
|
10
10
|
|
|
11
11
|
I guess this is actually a significant rewrite, so once I get some of the initial pieces done, it should be more obvious.
|
|
12
12
|
|
|
13
|
-
-- Arlen22
|
|
13
|
+
-- Arlen22
|
|
14
|
+
|
|
15
|
+
## Retrospective - 2025-06-24
|
|
16
|
+
|
|
17
|
+
It was a significant rewrite. I separated MWS into three packages, one package for the events, one package for generic web server stuff, and one package for all the MWS logic. Getting config from the database is pretty simple. We do it on startup and then if a setting can be changed live, we just update the config property. For those settings, we store the value in the request state to make sure each request uses the same setting for the duration of the request.
|
|
18
|
+
|
|
19
|
+
The only downside is that we have to make sure we import all the files that use the server events, but that's a small price to pay for the much higher flexibility. I'm sure there's a lint rule we could create somehow, but I haven't gotten to that yet.
|
|
@@ -12,8 +12,4 @@ There also isn't a good way to move tiddlers between levels. Admins will need to
|
|
|
12
12
|
|
|
13
13
|
I'm not good at wikitext, but I can provide the endpoints for all of these operations as well as the client-side adapters and actions to use them.
|
|
14
14
|
|
|
15
|
-
I also don't know why we aren't using the wiki mount point for the API, and putting the react UI under admin, since then it would free up the entire path space to use for a tree path structure.
|
|
16
|
-
|
|
17
|
-
I'm working on simplifying the internal code structure yet again, still focusing on getting everything up to speed with my latest ideas.
|
|
18
|
-
|
|
19
15
|
-- Arlen22
|
|
@@ -1,98 +1,28 @@
|
|
|
1
1
|
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
1. Web-based Administrative Interface
|
|
5
|
-
- Accessible to all users.
|
|
6
|
-
- Provides graphical interface for user operations
|
|
7
|
-
- Real-time validation and feedback
|
|
8
|
-
1. Command-line Interface (CLI) Tools
|
|
9
|
-
- Only available to server owner.
|
|
10
|
-
- Suitable for automation and scripting
|
|
11
|
-
- Enables batch operations
|
|
12
|
-
- Useful for system initialization
|
|
13
|
-
|
|
14
|
-
Each user account contains the following essential components:
|
|
15
|
-
|
|
16
|
-
- **Username**
|
|
17
|
-
- Must be unique across the system
|
|
18
|
-
- Case-sensitive
|
|
19
|
-
- Used for authentication and audit trails
|
|
20
|
-
- **Password**
|
|
21
|
-
- Stored using secure hashing algorithms
|
|
22
|
-
- Never stored in plaintext
|
|
23
|
-
- Subject to complexity requirements
|
|
24
|
-
- **Email**
|
|
25
|
-
- Eventually used for the obvious password reset.
|
|
26
|
-
- **Role Assignments**
|
|
27
|
-
- Multiple roles can be assigned
|
|
28
|
-
- Inherited permissions from all assigned roles
|
|
29
|
-
- Dynamic permission calculation based on role combination
|
|
30
|
-
|
|
31
|
-
## Access Levels
|
|
32
|
-
|
|
33
|
-
Conceptually, there are 6 access levels.
|
|
2
|
+
## Permissions
|
|
34
3
|
|
|
35
|
-
- **
|
|
36
|
-
- **
|
|
37
|
-
- **
|
|
38
|
-
- **Entity admin** - Users granted the admin *permission* on an entity. They cannot change the owner, but they can change the permissions of other users for that entity.
|
|
39
|
-
- **Entity write** - Users granted the write *permission* on an enitity. They can list, read, create, update, and delete tiddlers, but cannot change permissions.
|
|
40
|
-
- **Entity read** - Users granted the read *permission* on an entity. They can list and read tiddlers, but cannot do anything else.
|
|
4
|
+
- **READ** - Read tiddlers from an entity.
|
|
5
|
+
- **WRITE** - Write tiddlers to an entity.
|
|
6
|
+
- **ADMIN** - Update ACL for an entity.
|
|
41
7
|
|
|
42
8
|
## Entities
|
|
43
9
|
|
|
44
10
|
- **Bag** - A collection of tiddlers with unique titles
|
|
45
11
|
- **Recipe** - A stack of bags in a specific order. Bags may inherit the ACL of a recipe they are included in.
|
|
46
12
|
|
|
47
|
-
## Roles
|
|
13
|
+
## Roles (aka Groups)
|
|
48
14
|
|
|
49
15
|
- Roles have names and descriptions
|
|
50
16
|
- Multiple users can be assigned to a role
|
|
17
|
+
- Roles are given *permissions* on *entities*
|
|
51
18
|
|
|
52
|
-
##
|
|
53
|
-
|
|
54
|
-
- **READ** - Read tiddlers from an entity.
|
|
55
|
-
- **WRITE** - Write tiddlers to an entity.
|
|
56
|
-
- **ADMIN** - Update ACL for an entity.
|
|
57
|
-
|
|
58
|
-
## Admin
|
|
59
|
-
|
|
60
|
-
- There is an admin *role* and an admin *permission*.
|
|
61
|
-
- Roles are given specific permissions for specific entities (bags and recipes).
|
|
62
|
-
- The admin *role* has automatic admin *permission* for everything.
|
|
63
|
-
|
|
64
|
-
## ACL
|
|
65
|
-
|
|
66
|
-
- Grants the **Permission** for an **Entity** to a **Role**.
|
|
67
|
-
- Entities without an ACL are either public or private (configurable).
|
|
68
|
-
|
|
69
|
-
## Ownership
|
|
70
|
-
|
|
71
|
-
- Ownership of an entity grants the "admin" *permission*.
|
|
72
|
-
- Only site admins can change the owner of an entity.
|
|
73
|
-
- Users with "admin" *permission* **cannot** change ownership.
|
|
74
|
-
|
|
75
|
-
## User Types
|
|
76
|
-
|
|
77
|
-
#### Administrator (ADMIN) Role
|
|
78
|
-
|
|
79
|
-
- Full system access and configuration rights
|
|
80
|
-
- Most access checks are skipped
|
|
81
|
-
- Can create, modify, and delete user accounts
|
|
82
|
-
- Manages role assignments and permissions
|
|
83
|
-
- Has full permissions on all recipes and bags
|
|
84
|
-
|
|
85
|
-
#### Regular Users
|
|
86
|
-
|
|
87
|
-
- Created by administrators
|
|
88
|
-
- Permissions determined by assigned roles
|
|
89
|
-
- Access limited to specific recipes based on role permissions
|
|
90
|
-
- Access to recipes without an ACL is based on recipe config
|
|
19
|
+
## Access Levels
|
|
91
20
|
|
|
92
|
-
|
|
21
|
+
Conceptually, there are 6 access levels.
|
|
93
22
|
|
|
94
|
-
-
|
|
95
|
-
-
|
|
96
|
-
-
|
|
97
|
-
-
|
|
98
|
-
-
|
|
23
|
+
- **Site owner** - has file system access to the server, and can run CLI commands. Presumably they also have a site admin account and they can always create one via the CLI.
|
|
24
|
+
- **Site admin** - Users with the admin *role*. They can assign owners and change permissions, and have full read and write access.
|
|
25
|
+
- **Entity owner** - Owner of an entity (bag or recipe). They can change permissions for that entity, and have full read and write access.
|
|
26
|
+
- **Entity admin** - Granted admin *permission*, they can manage permissions for the entity.
|
|
27
|
+
- **Entity write** - Granted write *permission*, they can list, read, create, update, and delete tiddlers, but cannot change permissions.
|
|
28
|
+
- **Entity read** - Granted read *permission* on an entity. They can list and read tiddlers, but cannot do anything else.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
|
|
2
|
+
`ignore`
|
|
3
|
+
: `state.data` will be undefined. `state.reader` will be draining or already closed.
|
|
4
|
+
|
|
5
|
+
`stream`
|
|
6
|
+
: `state.data` will be undefined. You must call `state.reader` to get the request.
|
|
7
|
+
|
|
8
|
+
`buffer`
|
|
9
|
+
: `state.data` will be a Buffer.
|
|
10
|
+
|
|
11
|
+
`string`
|
|
12
|
+
: `state.data` will be a string.
|
|
13
|
+
|
|
14
|
+
`json`
|
|
15
|
+
: `state.data` will be read as a string, same as `string` and then parsed as JSON, with some sanity checks. If the string is zero-length, undefined will be returned without attempting to parse. This is the only case where undefined can be returned. If the JSON fails to parse, a `400 INVALID` response will be sent. `__proto__` and `constructor.prototype` are also checked.
|
|
16
|
+
|
|
17
|
+
`www-form-urlencoded` and `www-form-urlencoded-urlsearchparams`
|
|
18
|
+
: Parse the body using `URLSearchParams` optionally calling `Object.entries` on it.
|
|
19
|
+
: <div style="color: rgb(212, 212, 212); background-color: rgb(30, 30, 30); font-family: "Fira Code", "Cascadia Code", Consolas, "Courier New", monospace, Consolas, "Courier New", monospace; font-size: 15px; line-height: 20px; white-space: pre;"><div><span style="color: #569cd6;">const</span> <span style="color: #4fc1ff;">data</span> = <span style="color: #4fc1ff;">state</span>.<span style="color: #9cdcfe;">data</span> = <span style="color: #569cd6;">new</span> <span style="color: #4ec9b0;">URLSearchParams</span>((<span style="color: #c586c0;">await</span> <span style="color: #4fc1ff;">state</span>.<span style="color: #dcdcaa;">readBody</span>()).<span style="color: #dcdcaa;">toString</span>(<span style="color: #ce9178;">"utf8"</span>));</div><div><span style="color: #c586c0;">if</span> (<span style="color: #4fc1ff;">state</span>.<span style="color: #9cdcfe;">bodyFormat</span> === <span style="color: #ce9178;">"www-form-urlencoded"</span>) <span style="color: #4fc1ff;">state</span>.<span style="color: #9cdcfe;">data</span> = <span style="color: #4ec9b0;">Object</span>.<span style="color: #dcdcaa;">fromEntries</span>(<span style="color: #4fc1ff;">data</span>);</div></div>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
[[Client Plugins]] are normal [[TiddlyWiki]] plugins. They are cached on the server and served directly to the client as needed. [[Server Plugins]], perhaps acting as third-party plugin libraries, may register additional [[Client Plugins]] and either add them to the cache immediately (if it's some small built-in plugin) or only when a recipe requires them (like a plugin library would).
|
|
2
|
+
|
|
3
|
+
On startup, all server plugins are called to generate their client plugins. The client plugins are saved in `cache/${path}/plugin.*`, using a relative path of the plugin's choosing. The same thing happens when a recipe's list of plugins changes.
|
|
4
|
+
|
|
5
|
+
The wiki index file itself is also rendered with an empty store and saved at `cache/tiddlywiki5.html`.
|
|
6
|
+
|
|
7
|
+
When a wiki page is opened, the index file is loaded and parsed. Plugins are either read directly into the store area, or script tags are inserted which point to the location of the cache folder.
|
|
8
|
+
|
|
9
|
+
MWS saves a hash of the plugin in memory so it can be served as an external JavaScript file with the script integrity attribute. The advantage of external JavaScript files is that the browser can cache them on subsequent page loads, reducing bytes transferred. Plugins can also be served directly in the index file, just like a normal single-file TiddlyWiki would. Regardless of which option is used, MWS optimizes memory usage by piping the file directly into the response (and onto the network) rather than reading everything into memory first.
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
@@ -3,15 +3,16 @@ The MultiWikiServer HTTP API provides management and tiddler endpoints.
|
|
|
3
3
|
The design goals of the API are:
|
|
4
4
|
|
|
5
5
|
- Connect the client and server as transparently as possible.
|
|
6
|
-
- Be easy to understand and use via
|
|
6
|
+
- Be easy to understand and use via JavaScript.
|
|
7
7
|
- Have strict validation of incoming requests.
|
|
8
8
|
|
|
9
9
|
## Management
|
|
10
10
|
|
|
11
11
|
- On the client, most request paths are defined by a single adaptor function which accepts the input for the server and returns a promise which resolves to the server's parsed response.
|
|
12
12
|
- The server may throw a user error (or a string), which is expected to return to the client. It should give them an actionable understanding of what went wrong.
|
|
13
|
-
- The API essentially forwards a function call from the client to the server, using `fetch`. It expects a Javascript client, and is not intended to support form submissions directly.
|
|
14
13
|
|
|
15
14
|
## Tiddler
|
|
16
15
|
|
|
17
|
-
The tiddler API was based on [the API of TiddlyWeb](https://tank.peermore.com/tanks/tiddlyweb/HTTP%20API), first developed in 2008 by Chris Dent, but is more oriented around JSON and Typescript.
|
|
16
|
+
The tiddler API was based on [the API of TiddlyWeb](https://tank.peermore.com/tanks/tiddlyweb/HTTP%20API), first developed in 2008 by Chris Dent, but is more oriented around JSON and Typescript.
|
|
17
|
+
|
|
18
|
+
The concept of resources is central to the API and in the future it will hopefully be adapted to serve static versions of tiddlers.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
created: 20250417170314382
|
|
2
|
-
modified:
|
|
2
|
+
modified: 20250612222324438
|
|
3
3
|
tags: TableOfContents
|
|
4
4
|
title: HelloThere
|
|
5
5
|
type: text/vnd.tiddlywiki
|
|
@@ -19,4 +19,4 @@ Planned features include:
|
|
|
19
19
|
* Instantaneous synchronisation of changes between the server and all connected clients
|
|
20
20
|
* Workflow processing on the server, for example to automatically compress images, or to archive webpages
|
|
21
21
|
|
|
22
|
-
MWS is currently [[under development at GitHub|https://github.com/TiddlyWiki/MultiWikiServer]] but it is already functional and usable.
|
|
22
|
+
MWS is currently [[under development at GitHub|https://github.com/TiddlyWiki/MultiWikiServer]] but it is already functional and usable, [[except for user security|Security]].
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
created: 20241105133737778
|
|
2
|
-
modified:
|
|
2
|
+
modified: 20250612235731394
|
|
3
3
|
tags: TableOfContents
|
|
4
4
|
title: Installation
|
|
5
5
|
type: text/vnd.tiddlywiki
|
|
@@ -25,9 +25,8 @@ To update your copy of MWS in the future with newer changes will require re-down
|
|
|
25
25
|
|
|
26
26
|
!!! Git repo
|
|
27
27
|
|
|
28
|
-
It is
|
|
28
|
+
It is recommended to save a history of your project configuration using git,
|
|
29
29
|
|
|
30
30
|
* On Windows you can use [[GitHub Desktop|https://github.com/apps/desktop]].
|
|
31
31
|
* On Linux, git is usually preinstalled or available via the default package manager for your distro.
|
|
32
32
|
|
|
33
|
-
If you decide to do this, you should move the wiki folder out of the project folder, and change the `wikiPath` setting accordingly.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
|
|
2
|
+
If a user can write to a bag in a recipe, they can insert wiki-text which exports all the tiddlers in all recipes which contain that bag.
|
|
3
|
+
|
|
4
|
+
There are no real mitigations to this which can mitigate this completely, but there are some partial solutions which may help.
|
|
5
|
+
|
|
6
|
+
- Only allow loading modules from some bags.
|
|
7
|
+
- Partitioned bags which only allow each user to write tiddlers prefixed with their username.
|
|
8
|
+
- Use Content-Security-Policy headers to make the webpage read-only and block network requests.
|
|
9
|
+
|
|
10
|
+
I think what it really comes down to is that if you can't trust your users, don't give them write access.
|
|
11
|
+
|
|
12
|
+
Don't add untrusted bags to your recipes.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
Oracles are clues that give information about a response without revealing the actual response.
|
|
2
|
+
|
|
3
|
+
Obviously none of this matters if your data isn't encrypted with HTTPS, since it's all open for everyone to read. But if it's encrypted, there are still ways of determining content.
|
|
4
|
+
|
|
5
|
+
## Compression Oracles
|
|
6
|
+
|
|
7
|
+
A compression oracle is when an attack takes advantage of the deduplication that compression attempts to do by somehow managing to get their own plaintext inserted into the compression stream and then checking whether the compressed output increases in size or not. If it doesn't, then obviously that particularly plaintext was already in the response for that request.
|
|
8
|
+
|
|
9
|
+
## Length Oracle
|
|
10
|
+
|
|
11
|
+
A similar attack involves inspecting the request length to determine whether a request returned any results. This is especially true of search features. A very big response implies returned results and a very tiny response implies no results. But there are also other ways to use the length which can come down to determining the exact number of bytes returned.
|
|
12
|
+
|
|
13
|
+
### Mitigations for normal oracles
|
|
14
|
+
|
|
15
|
+
The attacks are usually done based on the timing of the response, so even if the response itself is opaque, the timing can usually still be inferred.
|
|
16
|
+
|
|
17
|
+
- Disable compression (ultimate mitigation but there are better solutions)
|
|
18
|
+
- Disable third-party cookies (SameSite=strict) so cookies are only sent for requests that originate from a loaded webpage. However, this prevents the cookie from being sent to the initial page load.
|
|
19
|
+
- We could set two cookies and only enable compression if the cookie with SameSite=strict is present. Any code which can make a SameSite=strict request is normally considered privelaged code anyway, so we have bigger problems if an attacker can do that.
|
|
20
|
+
|
|
21
|
+
## MWS-specific oracles
|
|
22
|
+
|
|
23
|
+
A cross-bag compression oracle would allow an attacker with write access in one bag to infer the contents of a different bag in the recipe which they do not have access to by somehow attacking someone who does have access to that recipe and watching how the browser compresses various things. Without directly reading the bag's contents, they can write to the bag they have access to and watch the responses being sent to the other user to infer the contents of the recipe overall.
|
|
24
|
+
|
|
25
|
+
If batching is enabled, and if updates have side effects which trigger a save which is then loaded by other browsers, and if the attacker manages to add a second save with the correct timing to load in the same batch as the update of the side effect, an oracle attack can occur.
|
|
26
|
+
|
|
27
|
+
## MWS mitigations
|
|
28
|
+
|
|
29
|
+
- The simplest mitigation is to never compress the contents of two bags together.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<<toc>>
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
|
|
2
|
+
1. **Entry Point**: `Router.handle()`
|
|
3
|
+
- Takes HTTP/HTTP2 request and response objects
|
|
4
|
+
- Wraps `handleRequest()` in error handling
|
|
5
|
+
|
|
6
|
+
2. **Main Request Processing**: `Router.handleRequest()`
|
|
7
|
+
- Emit middleware event
|
|
8
|
+
- Apply Helmet middleware
|
|
9
|
+
- Create Streamer instance
|
|
10
|
+
- Call `handleStreamer()`
|
|
11
|
+
|
|
12
|
+
3. **Stream Processing**: `Router.handleStreamer()`
|
|
13
|
+
- Emits streamer event
|
|
14
|
+
- Finds matching route using `findRoute()`
|
|
15
|
+
- Performs security checks (CSRF protection)
|
|
16
|
+
- Processes request body based on `bodyFormat`
|
|
17
|
+
- Creates `ServerRequest` instance
|
|
18
|
+
- Calls `handleRoute()`
|
|
19
|
+
|
|
20
|
+
4. **Route Matching**: `Router.findRoute()` and `findRouteRecursive()`
|
|
21
|
+
- Recursively matches URL path against defined routes
|
|
22
|
+
- Handles nested routes
|
|
23
|
+
- Matches HTTP methods
|
|
24
|
+
- Returns array of matched route segments
|
|
25
|
+
|
|
26
|
+
5. **Route Handling**: `Router.handleRoute()`
|
|
27
|
+
- Executes handlers for matched routes in sequence
|
|
28
|
+
- Emits handle event
|
|
29
|
+
- Falls back to 404 if no handler sends response
|
|
30
|
+
|
|
31
|
+
## Body Format Processing
|
|
32
|
+
|
|
33
|
+
The router supports multiple body formats:
|
|
34
|
+
- `stream`: Raw streaming data
|
|
35
|
+
- `string`: UTF-8 string
|
|
36
|
+
- `json`: Parsed JSON data
|
|
37
|
+
- `buffer`: Raw buffer
|
|
38
|
+
- `www-form-urlencoded`: Parsed form data as object
|
|
39
|
+
- `www-form-urlencoded-urlsearchparams`: Form data as URLSearchParams
|
|
40
|
+
- `ignore`: Ignores request body (default for GET/HEAD)
|
|
41
|
+
|
|
42
|
+
## Security Features
|
|
43
|
+
|
|
44
|
+
- Built-in Helmet middleware for security headers
|
|
45
|
+
- CSRF protection via `x-requested-with` header checks
|
|
46
|
+
- JSON security parsing (protects against prototype pollution)
|
|
47
|
+
- Method matching validation
|
|
48
|
+
- Path validation
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
The routes are hierarchical, allowing for nested routes with inherited properties and progressive URL path matching.
|
|
52
|
+
|
|
53
|
+
It is important that the entire request path be awaited and eventually resolve or reject. A promise should never be left hanging. The Router class takes care of making sure every request has finished with some response, but if the promise never resolves or rejects, the request will eventually time out.
|