sumba 2.22.1 → 2.23.0
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/extend/bajo/hook/dobo.sumba-team-guard@after-action.js +6 -0
- package/extend/bajo/hook/dobo.sumba-user-guard@after-action.js +6 -0
- package/extend/bajo/hook/waibu-mpa@pre-parsing.js +4 -4
- package/extend/bajo/hook/waibu-rest-api@pre-parsing.js +4 -4
- package/extend/bajo/hook/waibu-static@pre-parsing.js +4 -4
- package/extend/bajo/hook/waibu@after-app-boot.js +5 -23
- package/extend/bajo/hook/waibu@pre-parsing.js +0 -5
- package/extend/bajo/intl/en-US.json +8 -6
- package/extend/dobo/fixture/route-guard.js +26 -0
- package/extend/dobo/model/route-guard.js +60 -0
- package/extend/waibuDb/schema/route-guard.js +15 -0
- package/extend/waibuMpa/extend/waibuAdmin/route/route-guard/@action.js +11 -0
- package/extend/waibuRestApi/route/manage/route-guard/model-builder.json +4 -0
- package/index.js +24 -41
- package/lib/util.js +43 -67
- package/package.json +1 -1
- package/wiki/CHANGES.md +5 -0
- package/extend/sumba/route-guard/anonymous.json +0 -10
- package/extend/sumba/route-guard/secure.json +0 -8
- package/lib/collect.js +0 -52
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { checkUserId, checkTeam, checkTheme, checkIconset,
|
|
1
|
+
import { checkUserId, checkTeam, checkTheme, checkIconset, checkInterSite } from '../../../lib/util.js'
|
|
2
2
|
|
|
3
3
|
const preParsing = {
|
|
4
4
|
level: 10,
|
|
5
5
|
handler: async function (req, reply) {
|
|
6
6
|
await checkTheme.call(this, req, reply)
|
|
7
7
|
await checkIconset.call(this, req, reply)
|
|
8
|
-
await checkUserId.call(this, req, reply, 'waibuMpa')
|
|
9
|
-
await checkTeam.call(this, req, reply, 'waibuMpa')
|
|
10
|
-
await
|
|
8
|
+
if (!await checkUserId.call(this, req, reply, 'waibuMpa')) return
|
|
9
|
+
if (!await checkTeam.call(this, req, reply, 'waibuMpa')) return
|
|
10
|
+
await checkInterSite.call(this, req, reply)
|
|
11
11
|
}
|
|
12
12
|
}
|
|
13
13
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { checkUserId, checkTeam,
|
|
1
|
+
import { checkUserId, checkTeam, checkInterSite } from '../../../lib/util.js'
|
|
2
2
|
|
|
3
3
|
const preParsing = {
|
|
4
4
|
level: 10,
|
|
5
5
|
handler: async function (req, reply) {
|
|
6
|
-
await checkUserId.call(this, req, reply, 'waibuRestApi')
|
|
7
|
-
await checkTeam.call(this, req, reply, 'waibuRestApi')
|
|
8
|
-
await
|
|
6
|
+
if (!await checkUserId.call(this, req, reply, 'waibuRestApi')) return
|
|
7
|
+
if (!await checkTeam.call(this, req, reply, 'waibuRestApi')) return
|
|
8
|
+
await checkInterSite.call(this, req, reply)
|
|
9
9
|
}
|
|
10
10
|
}
|
|
11
11
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { checkUserId, checkTeam,
|
|
1
|
+
import { checkUserId, checkTeam, checkInterSite } from '../../../lib/util.js'
|
|
2
2
|
|
|
3
3
|
const preParsing = {
|
|
4
4
|
level: 10,
|
|
5
5
|
handler: async function (req, reply) {
|
|
6
|
-
await checkUserId.call(this, req, reply, 'waibuStatic')
|
|
7
|
-
await checkTeam.call(this, req, reply, 'waibuStatic')
|
|
8
|
-
await
|
|
6
|
+
if (!await checkUserId.call(this, req, reply, 'waibuStatic')) return
|
|
7
|
+
if (!await checkTeam.call(this, req, reply, 'waibuStatic')) return
|
|
8
|
+
await checkInterSite.call(this, req, reply)
|
|
9
9
|
}
|
|
10
10
|
}
|
|
11
11
|
|
|
@@ -1,23 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
this.log.trace('collectingRouteGuards')
|
|
7
|
-
await collectRoutes.call(this, 'secure')
|
|
8
|
-
await runHook(`${this.ns}:afterCollectSecureRoutes`, this.secureRoutes, this.secureNegRoutes)
|
|
9
|
-
this.log.trace('secureRoutes%d', this.secureRoutes.length)
|
|
10
|
-
this.log.trace('secureNegRoutes%d', this.secureNegRoutes.length)
|
|
11
|
-
await collectRoutes.call(this, 'anonymous')
|
|
12
|
-
await runHook(`${this.ns}:afterCollectAnonymousRoutes`, this.anonymousRoutes, this.anonymousNegRoutes)
|
|
13
|
-
this.log.trace('anonRoutes%d', this.anonymousRoutes.length)
|
|
14
|
-
this.log.trace('anonNegRoutes%d', this.anonymousNegRoutes.length)
|
|
15
|
-
this.log.trace('collectingTeamGuards')
|
|
16
|
-
await collectTeam.call(this)
|
|
17
|
-
await runHook(`${this.ns}:afterCollectTeamRoutes`, this.teamRoutes, this.teamNegRoutes)
|
|
18
|
-
this.log.trace('teamRoutes%d', this.teamRoutes.length)
|
|
19
|
-
this.log.trace('teamNegRoutes%d', this.teamNegRoutes.length)
|
|
20
|
-
await runHook(`${this.ns}:afterBoot`)
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export default afterAppBoot
|
|
1
|
+
async function afterAppBoot () {
|
|
2
|
+
await this.getRouteGuards(true)
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
export default afterAppBoot
|
|
@@ -1,13 +1,8 @@
|
|
|
1
|
-
import { checkNoRouteSetting, checkNoRouteSettingKey } from '../../../lib/util.js'
|
|
2
|
-
|
|
3
1
|
const preParsing = {
|
|
4
2
|
level: 10,
|
|
5
3
|
handler: async function (req, reply) {
|
|
6
|
-
const { get } = this.app.lib._
|
|
7
4
|
const { getHostname } = this.app.waibu
|
|
8
5
|
req.site = await this.getSite(getHostname(req))
|
|
9
|
-
const routes = get(req.site, checkNoRouteSettingKey)
|
|
10
|
-
checkNoRouteSetting.call(this, req, routes)
|
|
11
6
|
}
|
|
12
7
|
}
|
|
13
8
|
|
|
@@ -61,11 +61,6 @@
|
|
|
61
61
|
"troubleTickets": "Trouble Tickets",
|
|
62
62
|
"guest": "Guest",
|
|
63
63
|
"warningMemberOnly%s": "Please authenticate yourself first, because the <a href=\"%s\">page<a> your're trying to access is a member only page",
|
|
64
|
-
"collectingRouteGuards": "Collecting route guards:",
|
|
65
|
-
"secureRoutes%d": "- Secure routes: %d",
|
|
66
|
-
"secureNegRoutes%d": "- Secure, negated routes: %d",
|
|
67
|
-
"anonRoutes%d": "- Anonymous routes: %d",
|
|
68
|
-
"anonNegRoutes%d": "- Anonymous, negated routes: %d",
|
|
69
64
|
"replies": "Replies",
|
|
70
65
|
"compose": "Compose",
|
|
71
66
|
"yourReply": "Your Reply",
|
|
@@ -136,6 +131,8 @@
|
|
|
136
131
|
"statusOpen": "Open",
|
|
137
132
|
"statusClosed": "Closed",
|
|
138
133
|
"allSites": "All Sites",
|
|
134
|
+
"permission": "Permission",
|
|
135
|
+
"routeGuard": "Route Guard",
|
|
139
136
|
"field": {
|
|
140
137
|
"currentPassword": "Current Password",
|
|
141
138
|
"newPassword": "New Password",
|
|
@@ -159,7 +156,12 @@
|
|
|
159
156
|
"team": "Team",
|
|
160
157
|
"ns": "Module's Namespace",
|
|
161
158
|
"value": "Value",
|
|
162
|
-
"notes": "Notes"
|
|
159
|
+
"notes": "Notes",
|
|
160
|
+
"path": "Path",
|
|
161
|
+
"inverse": "Inverse?",
|
|
162
|
+
"anonymous": "Anonymous?",
|
|
163
|
+
"methods": "Methods",
|
|
164
|
+
"teams": "Teams"
|
|
163
165
|
},
|
|
164
166
|
"validation": {
|
|
165
167
|
"password": {
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
const routes = [
|
|
2
|
+
'sumba:/your-stuff/**/*',
|
|
3
|
+
'sumba:/signout',
|
|
4
|
+
'sumba:/help/trouble-tickets/**/*',
|
|
5
|
+
'sumba.restapi:/user/api-key',
|
|
6
|
+
'sumba.restapi:/your-stuff/**/*',
|
|
7
|
+
'sumba.restapi:/manage/**/*',
|
|
8
|
+
'~sumba:/user/**/*',
|
|
9
|
+
'~sumba:/signin',
|
|
10
|
+
'~sumba.restapi:/user/access-token/**/*'
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
async function userGuard () {
|
|
14
|
+
return routes.map(r => {
|
|
15
|
+
const anonymous = r[0] === '~'
|
|
16
|
+
return {
|
|
17
|
+
path: anonymous ? r.slice(1) : r,
|
|
18
|
+
anonymous,
|
|
19
|
+
_immutable: true,
|
|
20
|
+
siteId: '?:SumbaSite::alias:default',
|
|
21
|
+
status: 'ACTIVE'
|
|
22
|
+
}
|
|
23
|
+
})
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export default userGuard
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
async function routeGuard () {
|
|
2
|
+
return {
|
|
3
|
+
connection: 'memory',
|
|
4
|
+
properties: [
|
|
5
|
+
'path,,255,true,true',
|
|
6
|
+
{
|
|
7
|
+
name: 'inverse',
|
|
8
|
+
type: 'boolean',
|
|
9
|
+
required: true,
|
|
10
|
+
default: false
|
|
11
|
+
}, {
|
|
12
|
+
name: 'anonymous',
|
|
13
|
+
type: 'boolean',
|
|
14
|
+
required: true,
|
|
15
|
+
default: false
|
|
16
|
+
}, {
|
|
17
|
+
name: 'methods',
|
|
18
|
+
type: 'array',
|
|
19
|
+
required: true,
|
|
20
|
+
default: ['GET', 'POST', 'UPDATE', 'DELETE'],
|
|
21
|
+
values: ['GET', 'POST', 'UPDATE', 'DELETE']
|
|
22
|
+
}, {
|
|
23
|
+
name: 'teams',
|
|
24
|
+
type: 'array',
|
|
25
|
+
default: [],
|
|
26
|
+
ref: {
|
|
27
|
+
teams: {
|
|
28
|
+
model: 'SumbaTeam',
|
|
29
|
+
field: 'alias',
|
|
30
|
+
searchField: 'name',
|
|
31
|
+
fields: ['alias', 'name']
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}, {
|
|
35
|
+
name: 'weight',
|
|
36
|
+
type: 'smallint',
|
|
37
|
+
default: 0
|
|
38
|
+
}
|
|
39
|
+
],
|
|
40
|
+
features: [
|
|
41
|
+
{
|
|
42
|
+
name: 'sumba:status',
|
|
43
|
+
values: ['ACTIVE', 'INACTIVE'],
|
|
44
|
+
default: 'ACTIVE'
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
name: 'dobo:unique',
|
|
48
|
+
fields: ['path', 'anonymous', 'methods', 'teams', 'inverse', 'weight', 'status', 'siteId']
|
|
49
|
+
},
|
|
50
|
+
'dobo:immutable',
|
|
51
|
+
'dobo:updatedAt',
|
|
52
|
+
'sumba:siteId'
|
|
53
|
+
],
|
|
54
|
+
options: {
|
|
55
|
+
persistence: false
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export default routeGuard
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
const action = {
|
|
2
|
+
method: ['GET', 'POST'],
|
|
3
|
+
title: 'routeGuard',
|
|
4
|
+
handler: async function (req, reply) {
|
|
5
|
+
const { importModule } = this.app.bajo
|
|
6
|
+
const crudSkel = await importModule('waibuAdmin:/lib/crud-skel.js')
|
|
7
|
+
return await crudSkel.call(this, 'SumbaRouteGuard', req, reply)
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export default action
|
package/index.js
CHANGED
|
@@ -152,6 +152,8 @@ async function factory (pkgName) {
|
|
|
152
152
|
getUserByTokenDur: '1m'
|
|
153
153
|
}
|
|
154
154
|
}
|
|
155
|
+
this.userGuards = []
|
|
156
|
+
this.teamGuards = []
|
|
155
157
|
this.unsafeUserFields = ['password']
|
|
156
158
|
this.selfBind(['createNewSite', 'removeSite', 'getSite', 'getUserById', 'getUserByToken', 'getUserByUsernamePassword'])
|
|
157
159
|
}
|
|
@@ -160,10 +162,6 @@ async function factory (pkgName) {
|
|
|
160
162
|
const { getPluginDataDir } = this.app.bajo
|
|
161
163
|
this.downloadDir = `${getPluginDataDir(this.ns)}/download`
|
|
162
164
|
this.app.lib.fs.ensureDirSync(this.downloadDir)
|
|
163
|
-
for (const type of ['secure', 'anonymous', 'team']) {
|
|
164
|
-
this[`${type}Routes`] = this[`${type}Routes`] ?? []
|
|
165
|
-
this[`${type}NegRoutes`] = this[`${type}NegRoutes`] ?? []
|
|
166
|
-
}
|
|
167
165
|
if (this.config.multiSite === true) {
|
|
168
166
|
this.config.multiSite = cloneDeep(defMultiSite)
|
|
169
167
|
this.config.multiSite.enabled = true
|
|
@@ -227,6 +225,11 @@ async function factory (pkgName) {
|
|
|
227
225
|
{ title: 'teamUser', href: `waibuAdmin:/${prefix}/team-user/list` },
|
|
228
226
|
{ title: 'teamSetting', href: `waibuAdmin:/${prefix}/team-setting/list` }
|
|
229
227
|
]
|
|
228
|
+
}, {
|
|
229
|
+
title: 'permission',
|
|
230
|
+
children: [
|
|
231
|
+
{ title: 'routeGuard', href: `waibuAdmin:/${prefix}/route-guard/list` }
|
|
232
|
+
]
|
|
230
233
|
}, {
|
|
231
234
|
title: 'supportSystem',
|
|
232
235
|
children: [
|
|
@@ -358,7 +361,7 @@ async function factory (pkgName) {
|
|
|
358
361
|
return true
|
|
359
362
|
}
|
|
360
363
|
|
|
361
|
-
|
|
364
|
+
checkPathsByRoute = ({ paths = [], method = 'GET', teams = [], guards = [] }) => {
|
|
362
365
|
const { includes } = this.app.lib.aneka
|
|
363
366
|
const { outmatch } = this.app.lib
|
|
364
367
|
|
|
@@ -366,9 +369,8 @@ async function factory (pkgName) {
|
|
|
366
369
|
const matchPath = outmatch(item.path)
|
|
367
370
|
for (const path of paths) {
|
|
368
371
|
if (matchPath(path)) {
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
if (item.teams.length === 0) return item
|
|
372
|
+
if (item.methods.includes(method)) {
|
|
373
|
+
if (teams.length === 0) return item
|
|
372
374
|
if (includes(teams, item.teams)) return item
|
|
373
375
|
}
|
|
374
376
|
}
|
|
@@ -376,19 +378,6 @@ async function factory (pkgName) {
|
|
|
376
378
|
}
|
|
377
379
|
}
|
|
378
380
|
|
|
379
|
-
checkPathsByRoute = ({ paths = [], method = 'GET', guards = [] }) => {
|
|
380
|
-
const { outmatch } = this.app.lib
|
|
381
|
-
for (const item of guards) {
|
|
382
|
-
const matchPath = outmatch(item.path)
|
|
383
|
-
for (const path of paths) {
|
|
384
|
-
if (matchPath(path)) {
|
|
385
|
-
const matchMethods = outmatch(item.methods, { separator: false })
|
|
386
|
-
if (matchMethods(method)) return item
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
|
-
}
|
|
391
|
-
|
|
392
381
|
checkPathsByGuard = ({ guards, paths }) => {
|
|
393
382
|
const { outmatch } = this.app.lib
|
|
394
383
|
const matcher = outmatch(guards)
|
|
@@ -535,31 +524,25 @@ async function factory (pkgName) {
|
|
|
535
524
|
return password
|
|
536
525
|
}
|
|
537
526
|
|
|
538
|
-
parseRouteGuard = item => {
|
|
539
|
-
const { routePath, routePathHandlers } = this.app.waibu
|
|
540
|
-
const { isString, isEmpty } = this.app.lib._
|
|
541
|
-
if (isString(item)) {
|
|
542
|
-
let [path, methods] = item.split('|').map(i => i.trim())
|
|
543
|
-
methods = isEmpty(methods) ? ['*'] : methods.split(',').map(i => i.trim())
|
|
544
|
-
item = { path, methods }
|
|
545
|
-
}
|
|
546
|
-
item.methods = item.methods ?? ['*']
|
|
547
|
-
if (item.methods.includes('*')) item.methods = ['*']
|
|
548
|
-
const [, routeHandler] = item.path.split(':')[0].split('.')
|
|
549
|
-
if (!isEmpty(routeHandler) && !routePathHandlers[routeHandler]) return
|
|
550
|
-
const rns = isEmpty(routeHandler) ? 'waibuMpa' : routePathHandlers[routeHandler].ns
|
|
551
|
-
if (!this.app[rns]) return
|
|
552
|
-
item.inverse = item.path[0] === '!'
|
|
553
|
-
if (item.inverse) item.path = item.path.slice(1)
|
|
554
|
-
item.path = routePath(item.path, { defFormat: false })
|
|
555
|
-
return item
|
|
556
|
-
}
|
|
557
|
-
|
|
558
527
|
hash = async (item) => {
|
|
559
528
|
const { hash } = this.app.bajoExtra
|
|
560
529
|
return await hash(item, this.config.auth.common.apiKey.algo)
|
|
561
530
|
}
|
|
562
531
|
|
|
532
|
+
getRouteGuards = async (reread) => {
|
|
533
|
+
const { getModel } = this.app.dobo
|
|
534
|
+
const { routePath } = this.app.waibu
|
|
535
|
+
const { map, orderBy } = this.app.lib._
|
|
536
|
+
if (!reread) return this.routeGuards
|
|
537
|
+
const model = getModel('SumbaRouteGuard')
|
|
538
|
+
const results = await model.findAllRecord({ query: { status: 'ACTIVE' } }, { noMagic: true, dataOnly: true })
|
|
539
|
+
this.routeGuards = orderBy(map(results, item => {
|
|
540
|
+
item.path = routePath(item.path)
|
|
541
|
+
return item
|
|
542
|
+
}), ['weight', 'path'])
|
|
543
|
+
return this.routeGuards
|
|
544
|
+
}
|
|
545
|
+
|
|
563
546
|
createNewSite = createNewSite
|
|
564
547
|
removeSite = removeSite
|
|
565
548
|
getSite = getSite
|
package/lib/util.js
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
|
-
export const checkNoRouteSettingKey = 'setting.waibu.noRoutes.$in'
|
|
2
|
-
|
|
3
1
|
export function parseNsSettings (ns, setting, items) {
|
|
4
|
-
const { trim, set, isPlainObject, isArray, isEmpty, find
|
|
2
|
+
const { trim, set, isPlainObject, isArray, isEmpty, find } = this.app.lib._
|
|
5
3
|
const { parseObject, dayjs } = this.app.lib
|
|
6
|
-
const { routePath } = this.app.waibu
|
|
7
4
|
|
|
8
5
|
for (const item of items) {
|
|
9
6
|
if (item.ns === '_var' || ns === '_var') continue
|
|
@@ -27,30 +24,6 @@ export function parseNsSettings (ns, setting, items) {
|
|
|
27
24
|
if ((isPlainObject(value) || isArray(value)) && isEmpty(value)) continue
|
|
28
25
|
set(setting, `${ns}.${item.key}`, value)
|
|
29
26
|
}
|
|
30
|
-
const key = checkNoRouteSettingKey.slice(checkNoRouteSettingKey.indexOf('.') + 1)
|
|
31
|
-
let noRoutes = get(setting, key, [])
|
|
32
|
-
if (noRoutes.length > 0) {
|
|
33
|
-
noRoutes = noRoutes.map(item => {
|
|
34
|
-
if (!isString(item)) return item
|
|
35
|
-
let [url, methods] = item.split('|')
|
|
36
|
-
if (methods === '*' || !methods) methods = 'GET,POST,PUT,DELETE'
|
|
37
|
-
methods = methods.split(',').map(m => m.trim().toUpperCase())
|
|
38
|
-
return { url: routePath(url), methods }
|
|
39
|
-
})
|
|
40
|
-
set(setting, key, noRoutes)
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export function checkNoRouteSetting (req, routes) {
|
|
45
|
-
const { isEmpty } = this.app.lib._
|
|
46
|
-
const { outmatch } = this.app.lib
|
|
47
|
-
if (isEmpty(routes)) return
|
|
48
|
-
for (const route of routes) {
|
|
49
|
-
const isMatchUrl = outmatch(route.url)
|
|
50
|
-
if (isMatchUrl(req.url) || isMatchUrl(req.routeOptions.url)) {
|
|
51
|
-
if (route.methods.includes(req.method)) throw this.error('accessDenied', { statusCode: 403 })
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
27
|
}
|
|
55
28
|
|
|
56
29
|
export function pathsToCheck (req, withHome) {
|
|
@@ -84,25 +57,20 @@ export async function checkTheme (req, reply) {
|
|
|
84
57
|
}
|
|
85
58
|
|
|
86
59
|
export async function checkTeam (req, reply, source) {
|
|
87
|
-
const { get, isEmpty } = this.app.lib._
|
|
88
60
|
if (!req.user) return
|
|
89
61
|
const { map } = this.app.lib._
|
|
90
62
|
const paths = pathsToCheck.call(this, req, true)
|
|
91
63
|
const teams = map(req.user.teams, 'alias')
|
|
92
|
-
|
|
93
|
-
if (
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
64
|
+
const allGuards = (await this.getRouteGuards()).filter(item => item.siteId === req.site.id + '' && item.teams.length > 0)
|
|
65
|
+
if (allGuards.length === 0) return // no route guarded
|
|
66
|
+
let match = this.checkPathsByRoute({ paths, method: req.method, teams, guards: allGuards.filter(item => !item.inverse) })
|
|
67
|
+
if (!match) return // route is NOT protected by team guard
|
|
68
|
+
if (match) {
|
|
69
|
+
const neg = this.checkPathsByRoute({ paths, method: req.method, teams, guards: allGuards.filter(item => item.inverse) })
|
|
70
|
+
if (neg) match = undefined
|
|
97
71
|
}
|
|
98
72
|
if (!match) throw this.error('accessDenied', { statusCode: 403 })
|
|
99
|
-
|
|
100
|
-
for (const team of (req.user.teams ?? [])) {
|
|
101
|
-
const items = get(team, checkNoRouteSettingKey, [])
|
|
102
|
-
if (isEmpty(items)) continue
|
|
103
|
-
routes.push(...items)
|
|
104
|
-
}
|
|
105
|
-
checkNoRouteSetting.call(this, req, routes)
|
|
73
|
+
// passed
|
|
106
74
|
}
|
|
107
75
|
|
|
108
76
|
export async function checkUserId (req, reply, source) {
|
|
@@ -132,46 +100,47 @@ export async function checkUserId (req, reply, source) {
|
|
|
132
100
|
}
|
|
133
101
|
|
|
134
102
|
const paths = pathsToCheck.call(this, req)
|
|
135
|
-
|
|
103
|
+
const allGuards = (await this.getRouteGuards()).filter(item => item.siteId === req.site.id + '')
|
|
104
|
+
if (allGuards.length === 0) return false // no routes protected
|
|
105
|
+
let securePath = await this.checkPathsByRoute({ paths, method: req.method, guards: allGuards.filter(item => !item.anonymous && !item.inverse) })
|
|
136
106
|
if (securePath) {
|
|
137
|
-
const neg = await this.checkPathsByRoute({ paths, method: req.method, guards:
|
|
107
|
+
const neg = await this.checkPathsByRoute({ paths, method: req.method, guards: allGuards.filter(item => !item.anonymous && item.inverse) })
|
|
138
108
|
if (neg) securePath = undefined
|
|
139
109
|
}
|
|
140
|
-
let anonymousPath = await this.checkPathsByRoute({ paths, method: req.method, guards:
|
|
110
|
+
let anonymousPath = await this.checkPathsByRoute({ paths, method: req.method, guards: allGuards.filter(item => item.anonymous && !item.inverse) })
|
|
141
111
|
if (anonymousPath) {
|
|
142
|
-
const neg = await this.checkPathsByRoute({ paths, method: req.method, guards:
|
|
112
|
+
const neg = await this.checkPathsByRoute({ paths, method: req.method, guards: allGuards.filter(item => item.anonymous && item.inverse) })
|
|
143
113
|
if (neg) anonymousPath = undefined
|
|
144
114
|
}
|
|
145
115
|
if (!securePath && !anonymousPath) {
|
|
146
116
|
if (userId) await setUser()
|
|
147
|
-
return
|
|
117
|
+
return false // regular, unguarded path. Not secure & not anonymous path
|
|
148
118
|
}
|
|
149
119
|
if (anonymousPath) {
|
|
150
|
-
if (!userId) return
|
|
120
|
+
if (!userId) return false
|
|
151
121
|
req.session.ref = req.url
|
|
152
122
|
return reply.redirectTo(routePath(this.config.redirect.signout))
|
|
153
123
|
}
|
|
154
|
-
if (
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
break
|
|
171
|
-
}
|
|
124
|
+
if (userId) {
|
|
125
|
+
await setUser()
|
|
126
|
+
return true
|
|
127
|
+
}
|
|
128
|
+
const silentOnError = this.config.auth[webApp].silentOnError ?? this.config.auth.common.silentOnError
|
|
129
|
+
const payload = silentOnError ? { noContent: true } : undefined
|
|
130
|
+
const authMethods = this.config.auth[webApp].methods ?? []
|
|
131
|
+
if (isEmpty(authMethods)) throw this.error('noAuthMethod', merge({ statusCode: 500 }, payload))
|
|
132
|
+
let success
|
|
133
|
+
for (const m of authMethods) {
|
|
134
|
+
const handler = this[camelCase(`verify ${m}`)]
|
|
135
|
+
if (!handler) throw this.error('invalidAuthMethod%s', m, merge({ statusCode: 500 }, payload))
|
|
136
|
+
const check = await handler(req, reply, source, payload)
|
|
137
|
+
if (check) {
|
|
138
|
+
success = check
|
|
139
|
+
break
|
|
172
140
|
}
|
|
173
|
-
if (!success) throw this.error('accessDeniedNoAuth', merge({ statusCode: 403 }, payload))
|
|
174
141
|
}
|
|
142
|
+
if (!success) throw this.error('accessDeniedNoAuth', merge({ statusCode: 403 }, payload))
|
|
143
|
+
return true
|
|
175
144
|
}
|
|
176
145
|
|
|
177
146
|
export async function latLngHook (body, options) {
|
|
@@ -181,7 +150,14 @@ export async function latLngHook (body, options) {
|
|
|
181
150
|
body[options.field] = round(body[options.field], options.scale)
|
|
182
151
|
}
|
|
183
152
|
|
|
184
|
-
|
|
153
|
+
/**
|
|
154
|
+
* If current route is an inter site route user is an inter site admin, then let it passed
|
|
155
|
+
*
|
|
156
|
+
* @param {Object} req - Request object
|
|
157
|
+
* @param {Object} reply - Reply object
|
|
158
|
+
* @returns
|
|
159
|
+
*/
|
|
160
|
+
export async function checkInterSite (req, reply) {
|
|
185
161
|
const { get } = this.app.lib._
|
|
186
162
|
const isinterSite = get(req, 'routeOptions.config.interSite')
|
|
187
163
|
const isInterSiteAdmin = get(req, 'user.interSiteAdmin')
|
package/package.json
CHANGED
package/wiki/CHANGES.md
CHANGED
package/lib/collect.js
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
export async function collect ({ type = '', handler, container, file, ns, dir }) {
|
|
2
|
-
const { readConfig } = this.app.bajo
|
|
3
|
-
const { parseRouteGuard } = this
|
|
4
|
-
const { camelCase, find, isEmpty } = this.app.lib._
|
|
5
|
-
let items = await readConfig(file, { ns, baseNs: this.ns, defValue: [] })
|
|
6
|
-
if (isEmpty(items)) items = []
|
|
7
|
-
for (let item of items) {
|
|
8
|
-
item = parseRouteGuard(item)
|
|
9
|
-
if (!item) continue
|
|
10
|
-
if (handler) await handler.call(this, item)
|
|
11
|
-
const guards = this[camelCase(`${type} ${item.reverse ? 'Neg' : ''} ${container}`)]
|
|
12
|
-
delete item.reverse
|
|
13
|
-
if (find(guards, { path: item.path })) continue
|
|
14
|
-
guards.push(item)
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
function collectHandler (item, keys = []) {
|
|
19
|
-
const { isString } = this.app.lib._
|
|
20
|
-
for (const k of keys) {
|
|
21
|
-
item[k] = item[k] ?? []
|
|
22
|
-
if (isString(item[k])) item[k] = item[k].split(',')
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export async function collectRoutes (type) {
|
|
27
|
-
const { eachPlugins } = this.app.bajo
|
|
28
|
-
const me = this
|
|
29
|
-
|
|
30
|
-
function handler (item) {
|
|
31
|
-
collectHandler.call(this, item, ['methods'])
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
await eachPlugins(async function ({ file, dir }) {
|
|
35
|
-
const { ns } = this
|
|
36
|
-
await collect.call(me, { type, container: 'Routes', handler, file, ns, dir })
|
|
37
|
-
}, { glob: `route-guard/${type}.*`, prefix: this.ns })
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export async function collectTeam () {
|
|
41
|
-
const { eachPlugins } = this.app.bajo
|
|
42
|
-
const me = this
|
|
43
|
-
|
|
44
|
-
function handler (item) {
|
|
45
|
-
collectHandler.call(this, item, ['methods', 'teams', 'features'])
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
await eachPlugins(async function ({ file, dir }) {
|
|
49
|
-
const { ns } = this
|
|
50
|
-
await collect.call(me, { type: 'team', container: 'Routes', handler, file, ns, dir })
|
|
51
|
-
}, { glob: 'route-guard/team.*', prefix: this.ns })
|
|
52
|
-
}
|