w-web-task 1.0.32 → 1.0.33

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.
@@ -29,7 +29,7 @@
29
29
  <nav >
30
30
 
31
31
 
32
- <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="WWebTask.html">WWebTask</a></li></ul><h3>Global</h3><ul><li><a href="global.html#createLockSave">createLockSave</a></li><li><a href="global.html#describeUpstream">describeUpstream</a></li><li><a href="global.html#maskQuery">maskQuery</a></li><li><a href="global.html#maskTok">maskTok</a></li><li><a href="global.html#maskUrl">maskUrl</a></li><li><a href="global.html#submitGuard">submitGuard</a></li><li><a href="global.html#wrapInjected">wrapInjected</a></li></ul>
32
+ <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="WWebTask.html">WWebTask</a></li></ul><h3>Global</h3><ul><li><a href="global.html#createAuthorizeExec">createAuthorizeExec</a></li><li><a href="global.html#createLockSave">createLockSave</a></li><li><a href="global.html#describeUpstream">describeUpstream</a></li><li><a href="global.html#maskQuery">maskQuery</a></li><li><a href="global.html#maskTok">maskTok</a></li><li><a href="global.html#maskUrl">maskUrl</a></li><li><a href="global.html#submitGuard">submitGuard</a></li><li><a href="global.html#wrapInjected">wrapInjected</a></li></ul>
33
33
 
34
34
  </nav>
35
35
 
@@ -169,7 +169,7 @@ export { maskTok, maskQuery, maskUrl }
169
169
  <br class="clear">
170
170
 
171
171
  <footer>
172
- Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Sun Oct 11 2026 16:44:52 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
172
+ Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Wed Oct 14 2026 08:01:17 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
173
173
  </footer>
174
174
 
175
175
  <script>prettyPrint();</script>
@@ -29,7 +29,7 @@
29
29
  <nav >
30
30
 
31
31
 
32
- <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="WWebTask.html">WWebTask</a></li></ul><h3>Global</h3><ul><li><a href="global.html#createLockSave">createLockSave</a></li><li><a href="global.html#describeUpstream">describeUpstream</a></li><li><a href="global.html#maskQuery">maskQuery</a></li><li><a href="global.html#maskTok">maskTok</a></li><li><a href="global.html#maskUrl">maskUrl</a></li><li><a href="global.html#submitGuard">submitGuard</a></li><li><a href="global.html#wrapInjected">wrapInjected</a></li></ul>
32
+ <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="WWebTask.html">WWebTask</a></li></ul><h3>Global</h3><ul><li><a href="global.html#createAuthorizeExec">createAuthorizeExec</a></li><li><a href="global.html#createLockSave">createLockSave</a></li><li><a href="global.html#describeUpstream">describeUpstream</a></li><li><a href="global.html#maskQuery">maskQuery</a></li><li><a href="global.html#maskTok">maskTok</a></li><li><a href="global.html#maskUrl">maskUrl</a></li><li><a href="global.html#submitGuard">submitGuard</a></li><li><a href="global.html#wrapInjected">wrapInjected</a></li></ul>
33
33
 
34
34
  </nav>
35
35
 
@@ -170,7 +170,7 @@ export { wrapInjected, describeUpstream }
170
170
  <br class="clear">
171
171
 
172
172
  <footer>
173
- Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Sun Oct 11 2026 16:44:52 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
173
+ Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Wed Oct 14 2026 08:01:17 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
174
174
  </footer>
175
175
 
176
176
  <script>prettyPrint();</script>
@@ -29,7 +29,7 @@
29
29
  <nav >
30
30
 
31
31
 
32
- <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="WWebTask.html">WWebTask</a></li></ul><h3>Global</h3><ul><li><a href="global.html#createLockSave">createLockSave</a></li><li><a href="global.html#describeUpstream">describeUpstream</a></li><li><a href="global.html#maskQuery">maskQuery</a></li><li><a href="global.html#maskTok">maskTok</a></li><li><a href="global.html#maskUrl">maskUrl</a></li><li><a href="global.html#submitGuard">submitGuard</a></li><li><a href="global.html#wrapInjected">wrapInjected</a></li></ul>
32
+ <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="WWebTask.html">WWebTask</a></li></ul><h3>Global</h3><ul><li><a href="global.html#createAuthorizeExec">createAuthorizeExec</a></li><li><a href="global.html#createLockSave">createLockSave</a></li><li><a href="global.html#describeUpstream">describeUpstream</a></li><li><a href="global.html#maskQuery">maskQuery</a></li><li><a href="global.html#maskTok">maskTok</a></li><li><a href="global.html#maskUrl">maskUrl</a></li><li><a href="global.html#submitGuard">submitGuard</a></li><li><a href="global.html#wrapInjected">wrapInjected</a></li></ul>
33
33
 
34
34
  </nav>
35
35
 
@@ -150,7 +150,7 @@ export default submitGuard
150
150
  <br class="clear">
151
151
 
152
152
  <footer>
153
- Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Sun Oct 11 2026 16:44:52 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
153
+ Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Wed Oct 14 2026 08:01:17 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
154
154
  </footer>
155
155
 
156
156
  <script>prettyPrint();</script>
package/g.mOrm.mjs CHANGED
@@ -11,13 +11,8 @@ let st = getSettings()
11
11
  let url = st.dbUrl
12
12
  let db = st.dbName
13
13
 
14
- //WServOrm
15
- let opt = {
16
- getUserById: null,
17
- useCheckUser: false,
18
- useExcludeWhenNotAdmin: false,
19
- }
20
- let r = WServOrm(ds, WOrm, url, db, opt)
14
+ //WServOrm(w-serv-orm 已移除之 useCheckUser / getUserById / useExcludeWhenNotAdmin 不再傳入, spec D17)
15
+ let r = WServOrm(ds, WOrm, url, db)
21
16
  let { woItems, procOrm } = r
22
17
 
23
18
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "w-web-task",
3
- "version": "1.0.32",
3
+ "version": "1.0.33",
4
4
  "main": "dist/w-web-task.umd.js",
5
5
  "dependencies": {
6
6
  "axios": "^1.18.1",
@@ -8,13 +8,13 @@
8
8
  "json5": "^2.2.3",
9
9
  "showdown": "^2.1.0",
10
10
  "w-aggrid-vue": "^2.1.8",
11
- "w-component-vue": "^2.5.28",
12
- "w-data-collector": "^1.0.43",
13
- "w-serv-hapi": "^1.1.5",
14
- "w-serv-orm": "^1.1.6",
15
- "w-syslog": "^1.0.32",
16
- "w-ui-loginout": "^1.0.31",
17
- "wsemi": "^1.9.12"
11
+ "w-component-vue": "^2.5.29",
12
+ "w-data-collector": "^1.0.46",
13
+ "w-serv-hapi": "^1.1.6",
14
+ "w-serv-orm": "^1.1.10",
15
+ "w-syslog": "^1.0.33",
16
+ "w-ui-loginout": "^1.0.32",
17
+ "wsemi": "^1.9.16"
18
18
  },
19
19
  "devDependencies": {
20
20
  "@vue/cli-plugin-babel": "^5.0.8",
@@ -29,8 +29,8 @@
29
29
  "eslint-plugin-vue": "^9.10.0",
30
30
  "vue": "^2.7.16",
31
31
  "vuex": "^3.6.2",
32
- "w-orm-lmdb": "^1.0.37",
33
- "w-package-tools": "^1.1.16",
32
+ "w-orm-lmdb": "^1.0.39",
33
+ "w-package-tools": "^1.1.18",
34
34
  "w-package-tools-e2e": "^1.0.6",
35
35
  "w-screenctl": "^1.0.25"
36
36
  },
@@ -22,9 +22,11 @@ import fsIsFile from 'wsemi/src/fsIsFile.mjs'
22
22
  import replace from 'wsemi/src/replace.mjs'
23
23
  import WServHapiServer from 'w-serv-hapi/src/WServHapiServer.mjs'
24
24
  import WServOrm from 'w-serv-orm/src/WServOrm.mjs'
25
+ import checkOptRemoved from 'w-serv-orm/src/checkOptRemoved.mjs'
25
26
  import procLang from './procLang.mjs'
26
27
  import procCore from './procCore.mjs'
27
28
  import createLockSave from './lockSave.mjs'
29
+ import createAuthorizeExec from './authorizeExec.mjs'
28
30
  import srLogInit from './srLog.mjs'
29
31
  import { maskTok, maskQuery } from './maskLog.mjs'
30
32
  import { wrapInjected } from './wrapInjected.mjs'
@@ -39,11 +41,23 @@ import ds from '../src/schema/index.mjs'
39
41
  * @param {String} url 輸入資料庫連線字串,例如w-orm-lmdb為'./db'
40
42
  * @param {String} db 輸入資料庫名稱字串
41
43
  * @param {Function} getUserByToken 輸入處理函數,函數會傳入使用者token,通過此函數處理後並回傳使用者資訊物件,並至少須提供'id'、'email'、'name'、'isAdmin'欄位,且'isAdmin'限輸入'y'或'n'
42
- * @param {Function} verifyClientUser 輸入驗證瀏覽使用者身份之處理函數,函數會傳入使用者資訊物件,通過此函數識別後回傳布林值,允許使用者回傳true,反之回傳false
43
- * @param {Function} verifyAppUser 輸入驗證應用程序使用者身份之處理函數,函數會傳入使用者資訊物件,通過此函數識別後回傳布林值,允許使用者回傳true,反之回傳false
44
+ * @param {Function} verifyClientUser 輸入驗證瀏覽使用者身份之處理函數,函數會傳入使用者資訊物件與來源字串(from),通過此函數識別後回傳布林值,允許使用者回傳true,反之回傳false。作用於登入檢查(/api/getUserByToken,from為'getUserByToken')與前端資料通道之每次請求(連線閘,from為w-converhp之apiType如'main'),兩者同一判定;拋錯或reject視同不允許
45
+ * @param {Function} verifyAppUser 輸入驗證應用程序使用者身份之處理函數,函數會傳入使用者資訊物件與來源字串(from,為API名稱),通過此函數識別後回傳布林值,允許使用者回傳true,反之回傳false。作用於對外HTTP REST API(agent面);拋錯或reject視同不允許
44
46
  * @param {Object} [opt={}] 輸入設定物件,預設{}
45
47
  * @param {Integer} [opt.serverPort=11008] 輸入伺服器通訊port,預設11008
46
- * @returns {Object} 回傳物件,其內server為hapi伺服器實體
48
+ * @param {String} [opt.subfolder=''] 輸入網站子目錄字串,例如'mtask',預設''
49
+ * @param {String} [opt.urlRedirect=''] 輸入未登入時導向之網址字串(例如SSO登入頁),預設''
50
+ * @param {String} [opt.showLanguage='y'] 輸入是否顯示語系選單字串,可選'y'、'n',預設'y'
51
+ * @param {String} [opt.language='eng'] 輸入初始語系字串,可選'eng'、'cht',預設'eng'
52
+ * @param {Object} [opt.webName={}] 輸入網站名稱物件,key為語系而值為字串,預設{}
53
+ * @param {Object} [opt.webDescription={}] 輸入網站說明物件,key為語系而值為字串,預設{}
54
+ * @param {String} [opt.webLogo=''] 輸入網站logo字串,預設''
55
+ * @param {Object} [opt.kpLangExt={}] 輸入擴充語系物件,預設{}
56
+ * @param {String} [opt.logFd='./logs'] 輸入後端log資料夾字串,相對路徑以建構時之工作目錄解析,資料夾不可建立時(例如上層為檔案)於建構時拋錯(w-syslog 1.0.33起;於資料庫建立之前),預設'./logs'
57
+ * @param {String} [opt.logInterval='hr'] 輸入後端log分檔模式字串,可選'day'、'hr',預設'hr'
58
+ * @param {Integer} [opt.archiveAfterDays=30] 輸入終態任務與舊訊息逾此天數搬至冷表之天數,小於等於0為停用,預設30
59
+ * 已移除之設定:useCheckUser、getUserById、useExcludeWhenNotAdmin(w-serv-orm已移除),給予undefined、null、false以外之值即於建構時拋錯(於任何副作用之前)
60
+ * @returns {Object} 回傳w-serv-hapi之伺服器事件物件,可監聽error事件;w-serv-hapi 1.1.6起另帶ready與stop,惟stop只停止伺服器與其下游,不釋放本套件之計時器(封存掃描、雙擊防護占位)與資料庫連線,本套件以結束行程收尾
47
61
  */
48
62
  function WWebTask(WOrm, url, db, getUserByToken, verifyClientUser, verifyAppUser, opt = {}) {
49
63
  let instWServHapiServer = null
@@ -91,6 +105,11 @@ function WWebTask(WOrm, url, db, getUserByToken, verifyClientUser, verifyAppUser
91
105
  }
92
106
 
93
107
 
108
+ //checkOptRemoved: w-serv-orm 已移除之 useCheckUser / getUserById / useExcludeWhenNotAdmin(spec D17), 本套件不讀不轉交;
109
+ //給予 undefined / null / false 以外之值即同步拋 w-serv-orm 之原文訊息. 置於任何副作用(srLog 之 log 目錄、資料庫)之前; 規則與訊息由 w-serv-orm 單一擁有
110
+ checkOptRemoved(opt)
111
+
112
+
94
113
  //serverPort
95
114
  let serverPort = get(opt, 'serverPort')
96
115
  if (!ispint(serverPort)) {
@@ -99,18 +118,6 @@ function WWebTask(WOrm, url, db, getUserByToken, verifyClientUser, verifyAppUser
99
118
  serverPort = cint(serverPort)
100
119
 
101
120
 
102
- //useCheckUser
103
- let useCheckUser = get(opt, 'useCheckUser', false)
104
-
105
-
106
- //getUserById
107
- let getUserById = get(opt, 'getUserById', null)
108
-
109
-
110
- //useExcludeWhenNotAdmin
111
- let useExcludeWhenNotAdmin = get(opt, 'useExcludeWhenNotAdmin', false)
112
-
113
-
114
121
  //webName
115
122
  let webName = get(opt, 'webName', {})
116
123
 
@@ -153,14 +160,13 @@ function WWebTask(WOrm, url, db, getUserByToken, verifyClientUser, verifyAppUser
153
160
  let kpLang = procLang({ kpLangExt, webName, webDescription })
154
161
 
155
162
 
156
- //srLog(後端 log;錯誤一律 log err-key 供識別)。須先於 WServOrm 建構:getUserById 於建構時即交給 WServOrm,其包裝要用 srLog
163
+ //srLog(後端 log;錯誤一律 log err-key 供識別)
157
164
  let srLog = srLogInit(opt)
158
165
 
159
166
  //注入函數一律經 wrapInjected 包裝後使用(W 契約,spec/設計要點與取捨.md D15):
160
- //部署方注入之 getUserByToken / verifyClientUser / verifyAppUser / getUserById 同步拋錯或 reject 時,視同否定結果(查無 → null、無權限 → false),
167
+ //部署方注入之 getUserByToken / verifyClientUser / verifyAppUser 同步拋錯或 reject 時,視同否定結果(查無 → null、無權限 → false),
161
168
  //走各呼叫點既有分支回自家 key;失敗原文(舊版 sso helper 為已代入權杖之完整網址)不上拋、不入 log,只記 describeUpstream 之 key 或型別。
162
169
  //以包裝版取代參數本身 → 其後所有呼叫點(含日後新增者)結構上只可能用到包裝版;包裝處記 warn(因),呼叫點記 error(果)。
163
- //getUserById 選填(useCheckUser=true 時由 WServOrm 呼叫;原 reject 原文經 execute 之 pm2resolve 回前端),有給才包裝,查無由 WServOrm 既有分支拒絕。
164
170
  let onInjectFail = (name) => {
165
171
  return (d) => {
166
172
  srLog.warn({ event: `inject-${name}-fail`, ...d })
@@ -169,20 +175,12 @@ function WWebTask(WOrm, url, db, getUserByToken, verifyClientUser, verifyAppUser
169
175
  getUserByToken = wrapInjected(getUserByToken, { failValue: null, onFail: onInjectFail('getUserByToken') })
170
176
  verifyClientUser = wrapInjected(verifyClientUser, { failValue: false, onFail: onInjectFail('verifyClientUser') })
171
177
  verifyAppUser = wrapInjected(verifyAppUser, { failValue: false, onFail: onInjectFail('verifyAppUser') })
172
- if (isfun(getUserById)) {
173
- getUserById = wrapInjected(getUserById, { failValue: null, onFail: onInjectFail('getUserById') })
174
- }
175
178
 
176
179
 
177
180
  //WServOrm
178
- let optWServOrm = {
179
- useCheckUser,
180
- getUserById,
181
- useExcludeWhenNotAdmin,
182
- }
183
181
  let wp = {}
184
182
  try {
185
- wp = WServOrm(ds, WOrm, url, db, optWServOrm)
183
+ wp = WServOrm(ds, WOrm, url, db)
186
184
  }
187
185
  catch (err) {
188
186
  //ORM 為必要依賴:初始化失敗即 fail-fast,不以 wp={} 帶 undefined woItems/procOrm 殘缺啟動
@@ -345,12 +343,21 @@ function WWebTask(WOrm, url, db, getUserByToken, verifyClientUser, verifyAppUser
345
343
 
346
344
  //p
347
345
  let p = {
348
- checkToken: async(token) => {
349
-
350
- //getTokenUser:與 HTTP 路徑同一規則(S8),不另寫第二份
351
- await getTokenUser(token)
346
+ //checkToken:資料通道之連線閘(verifyConn 用),回傳是否放行(spec D17 決策 3)。
347
+ //認證:getTokenUser,與 HTTP 路徑同一出口(S8);失敗 reject 自家 key(w-converhp 回 permission denied、不寫 srLog,D15)。
348
+ //授權:已包裝之 verifyClientUser(拋錯或 reject 視同 false 並記 inject warn),與登入檢查 getAndVerifyClientUser 同一判定;from 為 w-converhp 之 apiType。
349
+ checkToken: async(token, from = '') => {
350
+
351
+ //getTokenUser
352
+ let user = await getTokenUser(token)
353
+
354
+ //verifyClientUser
355
+ let b = verifyClientUser(user, from)
356
+ if (ispm(b)) {
357
+ b = await b
358
+ }
352
359
 
353
- return true
360
+ return !!b
354
361
  },
355
362
  }
356
363
 
@@ -950,15 +957,16 @@ function WWebTask(WOrm, url, db, getUserByToken, verifyClientUser, verifyAppUser
950
957
  ]
951
958
 
952
959
 
953
- //tableNamesExec, tableNamesSync
954
- //ORM 直通寫入僅開放純 CRUD 表 (channels/channelMembers); tasks/messages 之生命週期/原子寫入一律走 kpFunExt 業務函式
955
- //(對應 spec 設計總覽 §6.2 註 與 設計要點與取捨 D2), 避免前端 ORM 直寫繞過 kmx + 狀態守衛 + 身分權威.
956
- //tableNamesSync 須與 tableNamesExec 對齊: 同步引擎收到某表 tag 變更時會呼叫 kpExec[table].select() 去重抓,
957
- //若把無 exec binding 的 messages/tasks 放進 sync, client refreshTable 找不到 kpExec[messages]/[tasks] →
958
- //每次變更 emit error + 洩漏未解 promise + 該表 tag 永不更新. messages/tasks 前端一律走 $fapi getMessages/getTasks
959
- //按需拉取 (非 ORM change 推送), 故不放進 sync.
960
+ //tableNamesExec, tableNamesSync, methodsExec
961
+ //資料通道之表操作只開 select, 供前端同步 channels/channelMembers (spec D17 決策 2); 寫入一律走 kpFunExt 業務函式
962
+ //(D16 lockSave、確保成員列 kmx、D7 游標身分皆在其內), 避免前端或直打 /api/main 之 ORM 直寫繞過之 (2026-10-14 前曾開 insert/save/del).
963
+ //tasks/messages 之生命週期/原子寫入亦一律走 kpFunExt (對應 spec 設計總覽 §6.2 註 與 設計要點與取捨 D2).
964
+ //tableNamesSync 須與 tableNamesExec 對齊且 methodsExec 須含 select: 同步引擎收到某表 tag 變更時會呼叫 kpExec[table].select() 去重抓
965
+ //(w-serv-webdata 1.1.12 於建構時檢核). messages/tasks 前端一律走 $fapi getMessages/getTasks 按需拉取 (非 ORM change 推送), 故不放進 sync.
966
+ //methodsExec 為單一定義: 同時交 w-serv-hapi 綁定與 authorizeExec 判斷
960
967
  let tableNamesExec = ['channels', 'channelMembers']
961
968
  let tableNamesSync = tableNamesExec
969
+ let methodsExec = ['select']
962
970
 
963
971
 
964
972
  //WServHapiServer
@@ -982,11 +990,17 @@ function WWebTask(WOrm, url, db, getUserByToken, verifyClientUser, verifyAppUser
982
990
  return false
983
991
  }
984
992
 
985
- //checkToken:套件層連線閘僅做「token 認證」(解析 user + 驗欄位齊備). 授權屬套件使用者責任.
986
- let b = await p.checkToken(token)
993
+ //checkToken:token 認證(解析 user + 驗欄位齊備; 失敗 reject 自家 key)+ 瀏覽使用者授權(部署方之 verifyClientUser, 與登入檢查同一強度; spec D17 決策 3)
994
+ let b = await p.checkToken(token, apiType)
987
995
 
988
- srLog.info({ event: 'verifyConn', apiType }) //連線之 token 認證通過
989
- return b
996
+ //check
997
+ if (!b) {
998
+ srLog.error({ event: 'verifyConn', err: 'errUserNoPermission', apiType }) //授權不通過須入 log 供稽核/統計; 只記 key 與 apiType, 不記權杖與使用者物件
999
+ return false
1000
+ }
1001
+
1002
+ srLog.info({ event: 'verifyConn', apiType }) //連線之認證與授權通過
1003
+ return true
990
1004
  },
991
1005
  getUserIdByToken: async (token) => { //可使用async或sync函數
992
1006
  //fail-closed(S9,對齊 perm):token 非字串或查無 userId(含上游失敗經 wrapInjected 視同查無)一律 reject,
@@ -1008,7 +1022,8 @@ function WWebTask(WOrm, url, db, getUserByToken, verifyClientUser, verifyAppUser
1008
1022
  kpOrm: woItems,
1009
1023
  operOrm: procOrm, //procOrm的輸入為: userId, tableName, methodName, input
1010
1024
  tableNamesExec,
1011
- methodsExec: ['select', 'insert', 'save', 'del'], //mix需於procOrm內註冊以提供
1025
+ methodsExec,
1026
+ authorizeExec: createAuthorizeExec({ methodsExec, srLog }), //w-serv-webdata 1.1.7 起 useDbOrm=true 時必填; 只放行已識別使用者之 select, 拒絕記 srLog (spec D17)
1012
1027
  tableNamesSync,
1013
1028
  kpFunExt: { //接收參數第1個為userId, 之後才是前端給予參數 (皆經 wrapErrLog)
1014
1029
 
@@ -0,0 +1,57 @@
1
+ import get from 'lodash-es/get.js'
2
+ import isestr from 'wsemi/src/isestr.mjs'
3
+ import isearr from 'wsemi/src/isearr.mjs'
4
+ import isfun from 'wsemi/src/isfun.mjs'
5
+
6
+
7
+ /**
8
+ * 資料通道表操作之授權函數(交 w-serv-hapi / w-serv-webdata 之 opt.authorizeExec; spec D17 決策 2)
9
+ *
10
+ * w-serv-webdata 1.1.7 起 useDbOrm=true 時必填, 前端呼叫表操作(如同步之 channels.select)時於 operOrm 之前呼叫,
11
+ * 回傳嚴格等於 true 才放行, 其他值一律回應 'permission denied' 且不呼叫 operOrm.
12
+ * 本套件之資料通道只開放 methodsExec 所列方法(['select'], 供前端同步); 寫入一律經 kpFunExt(D16 lockSave、確保成員列 kmx、D7 游標身分皆在其內).
13
+ * 放行: userId 為非空字串, 且 methodName 屬 methodsExec; 回傳一律為布林.
14
+ * 拒絕: 回 false 並記 srLog.error({ event: 'authorizeExec', err, tableName, methodName }), userId 缺為 'errUserIdMissing', 方法不在清單為 'errUserNoPermission'.
15
+ * getUserIdByToken 已 fail-closed 且 w-serv-webdata 只綁定 methodsExec 之方法, 故兩個拒絕分支於正常呼叫不會發生, 屬縱深防護.
16
+ *
17
+ * @param {Object} opt 輸入設定物件
18
+ * @param {Array} opt.methodsExec 輸入允許之表操作方法陣列(須與交 w-serv-hapi 之 methodsExec 為同一陣列), 須為非空陣列
19
+ * @param {Object} opt.srLog 輸入後端 log 物件, 須具 error 函數
20
+ * @returns {Function} 回傳 ({ userId, tableName, methodName }) => Boolean
21
+ */
22
+ function createAuthorizeExec(opt = {}) {
23
+
24
+ //methodsExec
25
+ let methodsExec = get(opt, 'methodsExec')
26
+ if (!isearr(methodsExec)) {
27
+ throw new Error('invalid opt.methodsExec')
28
+ }
29
+
30
+ //srLog
31
+ let srLog = get(opt, 'srLog')
32
+ if (!isfun(get(srLog, 'error'))) {
33
+ throw new Error('invalid opt.srLog')
34
+ }
35
+
36
+ let authorizeExec = ({ userId, tableName, methodName } = {}) => {
37
+
38
+ //check userId
39
+ if (!isestr(userId)) {
40
+ srLog.error({ event: 'authorizeExec', err: 'errUserIdMissing', tableName, methodName })
41
+ return false
42
+ }
43
+
44
+ //check methodName
45
+ if (!methodsExec.includes(methodName)) {
46
+ srLog.error({ event: 'authorizeExec', err: 'errUserNoPermission', tableName, methodName })
47
+ return false
48
+ }
49
+
50
+ return true
51
+ }
52
+
53
+ return authorizeExec
54
+ }
55
+
56
+
57
+ export default createAuthorizeExec
package/srv.mjs CHANGED
@@ -23,10 +23,6 @@ let ssoAppToken = st.ssoAppToken
23
23
  let ssoLoginUrl = st.ssoLoginUrl
24
24
  let opt = {
25
25
 
26
- useCheckUser: false,
27
- getUserById: null,
28
- useExcludeWhenNotAdmin: false,
29
-
30
26
  serverPort: get(stApp, 'serverPort', 11008),
31
27
  subfolder: '', //mtask
32
28
  urlRedirect: ssoLoginUrl, //未登入時導向SSO登入頁, 本機測試時得先編譯, 再瀏覽: http://localhost:11008/
@@ -82,6 +78,11 @@ let getUserByToken = async (token) => {
82
78
  if (token === '{token-for-verify-throw}' && process.env.NODE_ENV !== 'production') {
83
79
  return { id: 'id-for-verify-throw', name: 'verify-throw', email: 'verify-throw@example.com', isAdmin: 'y' }
84
80
  }
81
+ //'{token-for-nonadmin}' 為測試用權杖 (test/api-dataChannel), 同樣受 NODE_ENV 守門: 解析為有效但非系統管理者之使用者 (isAdmin='n'),
82
+ //下方 verifyClientUser 拒絕之, 供驗證資料通道之連線閘與登入檢查同一授權強度 (spec D17).
83
+ if (token === '{token-for-nonadmin}' && process.env.NODE_ENV !== 'production') {
84
+ return { id: 'id-for-nonadmin', name: 'nonadmin', email: 'nonadmin@example.com', isAdmin: 'n' }
85
+ }
85
86
  //未設定 SSO app token 時(本機開發未接SSO), 不打SSO直接拒絕
86
87
  if (!ssoAppToken) {
87
88
  console.log('ssoAppToken 未設定, 略過 SSO 驗證')
@@ -108,8 +109,9 @@ let getUserByToken = async (token) => {
108
109
  }
109
110
 
110
111
  let verifyClientUser = (user, from) => {
111
- console.log('verifyClientUser/user', user)
112
- console.log('於生產環境時得加入限制瀏覽器使用者身份機制')
112
+ //不於每次呼叫印出使用者物件: 登入檢查與資料通道之連線閘(前端每 2 秒輪詢)皆經此函數 (spec D17; 同 w-web-perm srv.mjs)
113
+ // console.log('verifyClientUser/user', user)
114
+ //於生產環境時得加入限制瀏覽器使用者身份機制 (from 為 'getUserByToken' 或資料通道之 apiType, 如 'main')
113
115
  //測試用 (受 NODE_ENV 守門): 合成使用者 id-for-verify-throw (見 getUserByToken 之 '{token-for-verify-throw}') 一律拋出夾合成秘密之 Error
114
116
  if (get(user, 'id', '') === 'id-for-verify-throw' && process.env.NODE_ENV !== 'production') {
115
117
  throw new Error('SYNTH-VERIFY-SECRET-FOR-TEST')
@@ -119,8 +121,9 @@ let verifyClientUser = (user, from) => {
119
121
  }
120
122
 
121
123
  let verifyAppUser = (user, from) => {
122
- console.log('verifyAppUser/user', user)
123
- console.log('於生產環境時得加入限制應用程式使用者身份機制')
124
+ //不於每次呼叫印出使用者物件: agent 之每次 HTTP REST 請求皆經此函數 (與 verifyClientUser 對稱; 同 w-web-perm srv.mjs)
125
+ // console.log('verifyAppUser/user', user)
126
+ //於生產環境時得加入限制應用程式使用者身份機制
124
127
  //測試用 (受 NODE_ENV 守門): 合成使用者 id-for-verify-throw (見 getUserByToken 之 '{token-for-verify-throw}') 一律拋出夾合成秘密之 Error
125
128
  if (get(user, 'id', '') === 'id-for-verify-throw' && process.env.NODE_ENV !== 'production') {
126
129
  throw new Error('SYNTH-VERIFY-SECRET-FOR-TEST')