w-web-perm 1.1.16 → 1.1.17

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.
Files changed (69) hide show
  1. package/README.md +12 -2
  2. package/dist/index.tmp +1 -1
  3. package/dist/js/{app-legacy.307bef4f.js → app-legacy.a9d18af3.js} +1 -1
  4. package/dist/js/{app.307bef4f.js → app.a9d18af3.js} +1 -1
  5. package/dist/js/{chunk-vendors-legacy.6cc4d11e.js → chunk-vendors-legacy.154af6b2.js} +6 -6
  6. package/dist/js/{chunk-vendors.6cc4d11e.js → chunk-vendors.154af6b2.js} +6 -6
  7. package/dist/w-web-perm.umd.js +2 -2
  8. package/dist/w-web-perm.umd.js.map +1 -1
  9. package/docs/WWebPerm.html +6 -3
  10. package/docs/global.html +1 -1
  11. package/docs/index.html +1 -1
  12. package/docs/server_WWebPerm.mjs.html +11 -1
  13. package/docs/server_adminCheck.mjs.html +1 -1
  14. package/docs/server_cascadeWrite.mjs.html +1 -1
  15. package/docs/server_dataChannel.mjs.html +1 -1
  16. package/docs/server_keyCheck.mjs.html +1 -1
  17. package/docs/server_lockSave.mjs.html +1 -1
  18. package/docs/server_maskLog.mjs.html +1 -1
  19. package/docs/server_procCore.mjs.html +1 -1
  20. package/docs/server_routeResult.mjs.html +1 -1
  21. package/docs/server_staLogs_resolveShellWorker.mjs.html +1 -1
  22. package/docs/server_syncCore.mjs.html +1 -1
  23. package/docs/server_syncKeep.mjs.html +1 -1
  24. package/docs/server_tools_authRefsAudit.mjs.html +1 -1
  25. package/docs/server_tools_authRefsClean.mjs.html +1 -1
  26. package/docs/server_tools_fromTools.mjs.html +1 -1
  27. package/docs/server_tools_isMain.mjs.html +1 -1
  28. package/docs/server_tools_nameDupReport.mjs.html +1 -1
  29. package/docs/server_validateRows.mjs.html +1 -1
  30. package/docs/server_wrapInjected.mjs.html +1 -1
  31. package/docs/src_fetchJson.mjs.html +1 -1
  32. package/docs/src_getPermUserInfor.mjs.html +1 -1
  33. package/docs/src_js_applySaved.mjs.html +1 -1
  34. package/docs/src_js_cellEditing.mjs.html +1 -1
  35. package/docs/src_js_cvKpToArr.mjs.html +1 -1
  36. package/docs/src_js_cvKpToObj.mjs.html +1 -1
  37. package/docs/src_js_draftSync.mjs.html +1 -1
  38. package/docs/src_js_eachOwn.mjs.html +1 -1
  39. package/docs/src_js_editorRefRows.mjs.html +1 -1
  40. package/docs/src_js_externalRows.mjs.html +1 -1
  41. package/docs/src_js_externalUi.mjs.html +1 -1
  42. package/docs/src_js_findRefRows.mjs.html +1 -1
  43. package/docs/src_js_findTouchedDup.mjs.html +1 -1
  44. package/docs/src_js_fmtLossyMsg.mjs.html +1 -1
  45. package/docs/src_js_fromAudit.mjs.html +1 -1
  46. package/docs/src_js_getAddImpact.mjs.html +1 -1
  47. package/docs/src_js_getAuthWarn.mjs.html +1 -1
  48. package/docs/src_js_getCascadePreview.mjs.html +1 -1
  49. package/docs/src_js_getDelRefCount.mjs.html +1 -1
  50. package/docs/src_js_getEffMode.mjs.html +1 -1
  51. package/docs/src_js_getKpLossy.mjs.html +1 -1
  52. package/docs/src_js_getNameErrs.mjs.html +1 -1
  53. package/docs/src_js_getOwn.mjs.html +1 -1
  54. package/docs/src_js_getPropKey.mjs.html +1 -1
  55. package/docs/src_js_getRuleEnable.mjs.html +1 -1
  56. package/docs/src_js_isAuthMode.mjs.html +1 -1
  57. package/docs/src_js_joinNames.mjs.html +1 -1
  58. package/docs/src_js_legendFit.mjs.html +1 -1
  59. package/docs/src_js_pairRowsToSnapshot.mjs.html +1 -1
  60. package/docs/src_js_refAudit.mjs.html +1 -1
  61. package/docs/src_js_refCascade.mjs.html +1 -1
  62. package/docs/src_js_refIdentity.mjs.html +1 -1
  63. package/docs/src_js_relDialogSend.mjs.html +1 -1
  64. package/docs/src_js_rowDigest.mjs.html +1 -1
  65. package/docs/src_plugins_dataReloadGuard.mjs.html +1 -1
  66. package/docs/src_plugins_reuseDeletedIds.mjs.html +1 -1
  67. package/docs/src_plugins_submitGuard.mjs.html +1 -1
  68. package/package.json +2 -2
  69. package/server/WWebPerm.mjs +10 -0
package/README.md CHANGED
@@ -108,7 +108,8 @@ instWWebPerm.on('error', (err) => {
108
108
  | Entry | Who may use it | Where it is checked (`server/WWebPerm.mjs`) |
109
109
  |---|---|---|
110
110
  | Data channel `POST /api/main`: RPC (`getWebInfor`, `getStaEvent`, `getStaEventTable`, `updateTargets/Pemis/Grups/Users`), table `select`, system functions (`[sys:getFuncList]`, `[sys:getTableTags]`, `[sys:polling]`), connection gate | administrators | `verifyConn` → `checkToken` → `getAndVerifyAdminUser` (`from` = `'main'`) |
111
- | Data channel, executing identity (body `__sysToken__`, looked up before every function and table operation; the one exception is the system function `[sys:polling]`, whose body identity is checked by the framework from w-serv-webdata 1.1.16 on — its header token is always checked here) | administrators | `getUserIdByToken` → `getAndVerifyAdminUser(token, 'main')` |
111
+ | Data channel, executing identity (body `__sysToken__`, looked up before every function and table operation, and, from w-serv-webdata 1.1.16 on, for every `[sys:polling]` round that carries a `__sysToken__` key; a round without the key, or with an invalid `clientId`, is refused before any lookup) | administrators | `getUserIdByToken` → `getAndVerifyAdminUser(token, 'main')` |
112
+ | System functions `[sys:getFuncList]`, `[sys:getTableTags]`, `[sys:polling]` (`sysFuncsPublic: ['[sys:getFuncList]']`; since perm-run01 of 2026-10-25) | administrators. Only the function-name list `[sys:getFuncList]` is listed as public, and it still needs a valid administrator here (the connection gate comes first, and `getUserIdByToken` refuses an empty or non-administrator body token). `[sys:polling]` (takes the broadcasts and the table timestamps) and `[sys:getTableTags]` need a valid administrator token in the body (`__sysToken__`), which the bundled front end (w-serv-hapi 1.1.8) sends on every polling round; a poll **without** the `__sysToken__` key (front-end bundles built before this release) that has passed the connection gate and carries a valid `clientId` is refused with `[sys:polling] permission denied` (a request whose header token fails the gate is answered `permission denied` by the gate itself; an invalid `clientId` is answered `[sys:polling] invalid clientId` before any lookup) | `sysFuncsPublic` of `WServHapiServer`, then the same `verifyConn` and `getUserIdByToken` gates |
112
113
  | Upload and download routes (`/api/ulctr`, `/api/slc`, `/api/dwgfn`, `/api/dwgf`, `/api/dw`; `apiType` `upload-controller`, `upload-slice`, `download-get-filename`, `download-get-file`, `download`) | administrators | the same `verifyConn` → `checkToken` (`from` = the `apiType`) |
113
114
  | The four write functions | administrators (defense in depth) | `requireAdmin` (fresh read of the caller's row) |
114
115
  | Console login check `GET /api/getUserByToken` | administrators | handler → `getAndVerifyAdminUser(token, 'getUserByToken')` |
@@ -124,10 +125,19 @@ instWWebPerm.on('error', (err) => {
124
125
  - **Connection gate and executing identity (since 2026-10-23, perm-run03)**: a data-channel request carries two tokens: the `Authorization` header (checked by `verifyConn`) and the `__sysToken__` of the request body (looked up by `getUserIdByToken`, which decides the user a function runs as). Both go through the same full check (`getAndVerifyClientUser`, plus the administrator requirement above since perm-run01): your `getUserByToken` returns the user, the user must exist in the `users` table of this system (looked up by `mappingBy`) with `isActive: 'y'`, and your `verifyClientUser(user, from)` must return `true`. If the body token fails any step the function is **not executed** (nothing is written; the response carries a fixed message key such as `cannotFindUserFromToken`, `cannotGetUserFromPerm` or `userNoPermission`; srLog `getUserIdByToken-error`, never the token). The two tokens may belong to different users; each is verified, the framework does not compare them, and the function runs as the body token's user. Before this release `getUserIdByToken` only asked `getUserByToken` for an id, so a body token that was not in the `users` table, was disabled, or that `verifyClientUser` would refuse was accepted as long as the header token was valid.
125
126
  - **What `verifyClientUser` sees**: for the body token it is called with `from = 'main'` (the same `apiType` as the connection gate, the only channel on which the framework looks up the executing identity), so a policy that branches on `from` behaves the same for both. The id returned to the framework (and written to `userId` / `userIdUpdate`) is the id **of the user's row in the `users` table of this system**, not the id your `getUserByToken` reported; they are the same with the default `mappingBy: 'id'` for users created in the admin pages (and for external rows migrated from the old synchronization), and differ for users imported by `/syncAndReplaceTabs` after the upgrade (their `id` is generated; they are found by `srcKey`, see Upgrade Notes section 4) and whenever `mappingBy` is `'email'` or `'name'`.
126
127
  - **Function-level role check (behavior change)**: `updateTargets`, `updatePemis`, `updateGrups` and `updateUsers` now refuse a caller whose row in the `users` table is not active **and** does not have `isAdmin: 'y'`, with the fixed message key `userNotAdmin`, before anything is read or written (srLog `requireAdmin-error`: function name and user id only). The `users` table of this system is the authority; the `isAdmin` that your `getUserByToken` reports is not used for this check (as for `isAdmin` elsewhere). Until now these functions relied entirely on your `verifyClientUser`; if it let non-administrators in (a read-only viewer, for example), they could write. The bundled pages are administrator pages and are unaffected. Count `requireAdmin-error` in srLog to see whether anyone was relying on the old behavior. *(Since perm-run01 an ordinary user is already refused at the connection gate, before this check; `requireAdmin` remains as defense in depth and is only reachable if the caller's role is lowered between the gate and the function. The read-only functions are restricted as well, see "Administrators only" above.)*
127
- - **Public entries**: there are none apart from the static front-end files. `/api/getUserByToken` verifies a client user and requires an administrator (or a system-service application token), `/api/getPerm` verifies a client user (any role), `/api/getPermUserInfor` and `/syncAndReplaceTabs` verify an application user (administrator level required, then `verifyAppUser`); the data channel only offers `select` on the tables (all writes go through the four functions above).
128
+ - **Public entries**: there are none apart from the static front-end files (`sysFuncsPublic` lists `[sys:getFuncList]` as public, but this package's gates still require an administrator token for it, see the table above). Nothing in the bundled front end talks to the data channel before a token exists: it starts the data channel only after login succeeded (`useWaitToken: true`), so the screens before login (no token, redirect to the login system, ordinary user "no permission", refused token) do not need any public system function. `/api/getUserByToken` verifies a client user and requires an administrator (or a system-service application token), `/api/getPerm` verifies a client user (any role), `/api/getPermUserInfor` and `/syncAndReplaceTabs` verify an application user (administrator level required, then `verifyAppUser`); the data channel only offers `select` on the tables (all writes go through the four functions above).
128
129
 
129
130
  ## Upgrade Notes
130
131
 
132
+ ### Unreleased: system functions need an identity — `[sys:polling]` and `[sys:getTableTags]` are no longer public (2026-10-25, perm-run01 of this round, R-SYSFUNCS-01) — one behavior change
133
+
134
+ **1. Polling must carry the token; front-end bundles built before this release stop syncing until the page is reloaded (behavior change)**
135
+ - **What changes**: the framework (w-serv-webdata 1.1.16, via w-serv-hapi 1.1.8) lets the deployer decide which of its three system functions are callable without an identity (`sysFuncsPublic`; its default keeps all three public for compatibility). This package now sets `sysFuncsPublic: ['[sys:getFuncList]']`: `[sys:polling]` (takes the broadcasts and the table timestamps) and `[sys:getTableTags]` (table names and timestamps) need a valid administrator identity. The front-end element of w-serv-hapi 1.1.8 puts the user's token in the body of every polling round (`__sysToken__`, next to `clientId`) and the server looks it up with `getUserIdByToken` on every round that carries the key (the same full check as for any other call, administrators only). A polling round that has passed the connection gate and carries a valid `clientId`, but whose body has **no** `__sysToken__` key, or an empty or invalid one, is refused with the fixed message `[sys:polling] permission denied` and the framework emits an `error` event on the instance (`instWWebPerm.on('error', ...)`; a missing key is not looked up at all, an invalid token ends in `[sys:polling] verifyPolling error`); the refused round binds no identity and takes no broadcast. A request whose header token already fails the connection gate is answered `permission denied` by the gate itself, and one whose `clientId` is missing or not a non-empty string is answered `[sys:polling] invalid clientId` before any lookup; neither produces a polling `error` event.
136
+ - **Who is affected**: a browser that still runs a front-end bundle built **before** this release (a cached `index.html` / `js` file loaded after the upgrade): its polling has no `__sysToken__`, so it keeps showing "Logged in" and never loads the tables (checked with a real browser: the old bundle's polling is refused every round). A tab that was **already open and loaded** when the server is upgraded keeps showing the data it had but stops receiving updates, because its polling is refused from then on. **Reload the page** (hard reload if the old files are cached) to load the new bundle. Anyone who built his or her own front end with the `w-serv-hapi` client against this server must upgrade that client to 1.1.8 or later and give it `getToken` (the client sends the token with the polling only from that version on); a custom front end that switches to another user without reloading keeps its `clientId`, and the framework refuses another user's polling on that `clientId` until it times out (about 10 seconds), so reload instead.
137
+ - **What stays the same**: `[sys:getFuncList]` is listed as public, but in this package it still needs an administrator token: the connection gate refuses requests without an administrator `Authorization` header first, and `getUserIdByToken` refuses an empty or non-administrator body token, so the list is a statement of intent, not an anonymous door. Everything before login is unchanged: the bundled front end starts the data channel only after login succeeded (`useWaitToken: true`), so opening the site without a token (redirect to `urlRedirect`), with a refused token (redirect), or as an ordinary user ("No permission to enter the permission console") makes no data-channel request at all.
138
+ - **Dependencies**: `w-serv-hapi` `^1.1.8` (declares w-serv-webdata `^1.1.16`, which declares w-serv-broadcast `^1.1.11`; this release was built and tested with w-serv-broadcast 1.1.12, which a fresh install resolves — if your lockfile still pins an older w-serv-broadcast, update it, e.g. `npm update w-serv-broadcast`). With an older framework the option is ignored and all three functions stay public (`test/unit-sysFuncsSite.test.mjs` checks the installed versions).
139
+ - **Check before upgrading**: nothing to configure. After the upgrade, users who report "Logged in" that never finishes loading need a page reload. The refused rounds are visible as `error` events with `[sys:polling]` messages (count them in your `error` handler).
140
+
131
141
  ### Unreleased: application-system tokens (user purpose / system-service purpose), the administrator level on the application routes, `Bearer` only, route errors as fixed keys (2026-10-24, perm-run01 and perm-run02 of this round, R-APP-TOKEN-01) — one narrow breaking change, one behavior change and two fixes
132
142
 
133
143
  **1. The application routes need the administrator level — an application identity that is in no row of `users` and reports `isAdmin: 'y'` keeps working, with or without `isApp` (breaking only for application identities that do not report `isAdmin: 'y'`, or that match a `users` row that is not an active administrator)**
package/dist/index.tmp CHANGED
@@ -1,4 +1,4 @@
1
1
  <!doctype html><html xmlns="http://www.w3.org/1999/xhtml" lang="zh-tw"><head><meta http-equiv="content-type" content="text/html; charset=UTF-8"/><meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no,minimal-ui"><meta http-equiv="X-UA-Compatible" content="ie=edge"><meta name="referrer" content="strict-origin"><title></title><link _href="https://cdn.jsdelivr.net/npm/@mdi/font@7.4.47/css/materialdesignicons.min.css" rel="stylesheet"><link _href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.4.2/css/all.min.css" rel="stylesheet"><script>window.___pmwperm___={
2
2
  urlRedirect: '{urlRedirect}',
3
3
  language: '{language}',
4
- }</script><script defer="defer" src="{sfd}/js/chunk-vendors.6cc4d11e.js" type="module"></script><script defer="defer" src="{sfd}/js/app.307bef4f.js" type="module"></script><link href="{sfd}/css/chunk-vendors.3c580e72.css" rel="stylesheet"><link href="{sfd}/css/app.f24c5e50.css" rel="stylesheet"><script defer="defer" src="{sfd}/js/chunk-vendors-legacy.6cc4d11e.js" nomodule></script><script defer="defer" src="{sfd}/js/app-legacy.307bef4f.js" nomodule></script></head><body style="font-family:'Microsoft JhengHei','Avenir','Helvetica', 'Arial', 'sans-serif'; padding:0px; margin:0px;"><noscript><strong>We're sorry but w-component-vue doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div></body></html>
4
+ }</script><script defer="defer" src="{sfd}/js/chunk-vendors.154af6b2.js" type="module"></script><script defer="defer" src="{sfd}/js/app.a9d18af3.js" type="module"></script><link href="{sfd}/css/chunk-vendors.3c580e72.css" rel="stylesheet"><link href="{sfd}/css/app.f24c5e50.css" rel="stylesheet"><script defer="defer" src="{sfd}/js/chunk-vendors-legacy.154af6b2.js" nomodule></script><script defer="defer" src="{sfd}/js/app-legacy.a9d18af3.js" nomodule></script></head><body style="font-family:'Microsoft JhengHei','Avenir','Helvetica', 'Arial', 'sans-serif'; padding:0px; margin:0px;"><noscript><strong>We're sorry but w-component-vue doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div></body></html>