@budibase/backend-core 3.2.4 → 3.2.6
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/dist/index.js.map +1 -1
- package/dist/index.js.meta.json +1 -1
- package/dist/package.json +11 -4
- package/dist/plugins.js.meta.json +1 -1
- package/package.json +11 -4
- package/src/accounts/accounts.ts +0 -82
- package/src/accounts/api.ts +0 -59
- package/src/accounts/index.ts +0 -1
- package/src/auth/auth.ts +0 -210
- package/src/auth/index.ts +0 -1
- package/src/auth/tests/auth.spec.ts +0 -14
- package/src/blacklist/blacklist.ts +0 -54
- package/src/blacklist/index.ts +0 -1
- package/src/blacklist/tests/blacklist.spec.ts +0 -46
- package/src/cache/appMetadata.ts +0 -88
- package/src/cache/base/index.ts +0 -150
- package/src/cache/docWritethrough.ts +0 -105
- package/src/cache/generic.ts +0 -33
- package/src/cache/index.ts +0 -8
- package/src/cache/invite.ts +0 -86
- package/src/cache/passwordReset.ts +0 -49
- package/src/cache/tests/docWritethrough.spec.ts +0 -296
- package/src/cache/tests/user.spec.ts +0 -145
- package/src/cache/tests/writethrough.spec.ts +0 -139
- package/src/cache/user.ts +0 -154
- package/src/cache/writethrough.ts +0 -133
- package/src/configs/configs.ts +0 -263
- package/src/configs/index.ts +0 -1
- package/src/configs/tests/configs.spec.ts +0 -184
- package/src/constants/db.ts +0 -75
- package/src/constants/index.ts +0 -2
- package/src/constants/misc.ts +0 -36
- package/src/context/Context.ts +0 -14
- package/src/context/identity.ts +0 -58
- package/src/context/index.ts +0 -3
- package/src/context/mainContext.ts +0 -422
- package/src/context/tests/index.spec.ts +0 -255
- package/src/context/types.ts +0 -26
- package/src/db/Replication.ts +0 -94
- package/src/db/couch/DatabaseImpl.ts +0 -511
- package/src/db/couch/connections.ts +0 -89
- package/src/db/couch/index.ts +0 -4
- package/src/db/couch/pouchDB.ts +0 -97
- package/src/db/couch/pouchDump.ts +0 -0
- package/src/db/couch/tests/DatabaseImpl.spec.ts +0 -118
- package/src/db/couch/utils.ts +0 -55
- package/src/db/db.ts +0 -34
- package/src/db/errors.ts +0 -14
- package/src/db/index.ts +0 -12
- package/src/db/instrumentation.ts +0 -199
- package/src/db/lucene.ts +0 -721
- package/src/db/searchIndexes/index.ts +0 -1
- package/src/db/searchIndexes/searchIndexes.ts +0 -62
- package/src/db/tests/DatabaseImpl.spec.ts +0 -55
- package/src/db/tests/connections.spec.ts +0 -22
- package/src/db/tests/index.spec.ts +0 -32
- package/src/db/tests/lucene.spec.ts +0 -400
- package/src/db/tests/pouch.spec.js +0 -62
- package/src/db/tests/utils.spec.ts +0 -63
- package/src/db/utils.ts +0 -208
- package/src/db/views.ts +0 -245
- package/src/docIds/conversions.ts +0 -60
- package/src/docIds/ids.ts +0 -126
- package/src/docIds/index.ts +0 -2
- package/src/docIds/newid.ts +0 -5
- package/src/docIds/params.ts +0 -189
- package/src/docUpdates/index.ts +0 -24
- package/src/environment.ts +0 -293
- package/src/errors/errors.ts +0 -119
- package/src/errors/index.ts +0 -1
- package/src/events/analytics.ts +0 -6
- package/src/events/asyncEvents/index.ts +0 -2
- package/src/events/asyncEvents/publisher.ts +0 -12
- package/src/events/asyncEvents/queue.ts +0 -22
- package/src/events/backfill.ts +0 -183
- package/src/events/documentId.ts +0 -56
- package/src/events/events.ts +0 -47
- package/src/events/identification.ts +0 -311
- package/src/events/index.ts +0 -15
- package/src/events/processors/AnalyticsProcessor.ts +0 -64
- package/src/events/processors/AuditLogsProcessor.ts +0 -92
- package/src/events/processors/LoggingProcessor.ts +0 -36
- package/src/events/processors/Processors.ts +0 -52
- package/src/events/processors/async/DocumentUpdateProcessor.ts +0 -38
- package/src/events/processors/index.ts +0 -19
- package/src/events/processors/posthog/PosthogProcessor.ts +0 -118
- package/src/events/processors/posthog/index.ts +0 -3
- package/src/events/processors/posthog/rateLimiting.ts +0 -106
- package/src/events/processors/posthog/tests/PosthogProcessor.spec.ts +0 -164
- package/src/events/processors/types.ts +0 -1
- package/src/events/publishers/account.ts +0 -41
- package/src/events/publishers/ai.ts +0 -21
- package/src/events/publishers/app.ts +0 -168
- package/src/events/publishers/auditLog.ts +0 -26
- package/src/events/publishers/auth.ts +0 -73
- package/src/events/publishers/automation.ts +0 -110
- package/src/events/publishers/backfill.ts +0 -74
- package/src/events/publishers/backup.ts +0 -42
- package/src/events/publishers/datasource.ts +0 -48
- package/src/events/publishers/email.ts +0 -17
- package/src/events/publishers/environmentVariable.ts +0 -38
- package/src/events/publishers/group.ts +0 -99
- package/src/events/publishers/index.ts +0 -25
- package/src/events/publishers/installation.ts +0 -38
- package/src/events/publishers/layout.ts +0 -26
- package/src/events/publishers/license.ts +0 -84
- package/src/events/publishers/org.ts +0 -37
- package/src/events/publishers/plugin.ts +0 -47
- package/src/events/publishers/query.ts +0 -89
- package/src/events/publishers/role.ts +0 -62
- package/src/events/publishers/rows.ts +0 -29
- package/src/events/publishers/screen.ts +0 -36
- package/src/events/publishers/serve.ts +0 -43
- package/src/events/publishers/table.ts +0 -70
- package/src/events/publishers/user.ts +0 -202
- package/src/events/publishers/view.ts +0 -107
- package/src/features/features.ts +0 -277
- package/src/features/index.ts +0 -2
- package/src/features/tests/features.spec.ts +0 -267
- package/src/features/tests/utils.ts +0 -64
- package/src/helpers.ts +0 -9
- package/src/index.ts +0 -59
- package/src/installation.ts +0 -115
- package/src/logging/alerts.ts +0 -26
- package/src/logging/correlation/correlation.ts +0 -15
- package/src/logging/correlation/index.ts +0 -1
- package/src/logging/correlation/middleware.ts +0 -18
- package/src/logging/index.ts +0 -4
- package/src/logging/pino/logger.ts +0 -239
- package/src/logging/pino/middleware.ts +0 -48
- package/src/logging/system.ts +0 -81
- package/src/logging/tests/system.spec.ts +0 -61
- package/src/middleware/adminOnly.ts +0 -9
- package/src/middleware/auditLog.ts +0 -6
- package/src/middleware/authenticated.ts +0 -247
- package/src/middleware/builderOnly.ts +0 -21
- package/src/middleware/builderOrAdmin.ts +0 -21
- package/src/middleware/contentSecurityPolicy.ts +0 -113
- package/src/middleware/csrf.ts +0 -81
- package/src/middleware/errorHandling.ts +0 -43
- package/src/middleware/index.ts +0 -24
- package/src/middleware/internalApi.ts +0 -23
- package/src/middleware/ip.ts +0 -12
- package/src/middleware/joi-validator.ts +0 -58
- package/src/middleware/matchers.ts +0 -39
- package/src/middleware/passport/datasource/google.ts +0 -102
- package/src/middleware/passport/local.ts +0 -54
- package/src/middleware/passport/sso/google.ts +0 -77
- package/src/middleware/passport/sso/oidc.ts +0 -152
- package/src/middleware/passport/sso/sso.ts +0 -138
- package/src/middleware/passport/sso/tests/google.spec.ts +0 -68
- package/src/middleware/passport/sso/tests/oidc.spec.ts +0 -144
- package/src/middleware/passport/sso/tests/sso.spec.ts +0 -197
- package/src/middleware/passport/utils.ts +0 -38
- package/src/middleware/querystringToBody.ts +0 -28
- package/src/middleware/tenancy.ts +0 -36
- package/src/middleware/tests/builder.spec.ts +0 -181
- package/src/middleware/tests/contentSecurityPolicy.spec.ts +0 -75
- package/src/middleware/tests/matchers.spec.ts +0 -100
- package/src/migrations/definitions.ts +0 -40
- package/src/migrations/index.ts +0 -2
- package/src/migrations/migrations.ts +0 -186
- package/src/migrations/tests/__snapshots__/migrations.spec.ts.snap +0 -11
- package/src/migrations/tests/migrations.spec.ts +0 -64
- package/src/objectStore/buckets/app.ts +0 -53
- package/src/objectStore/buckets/global.ts +0 -29
- package/src/objectStore/buckets/index.ts +0 -3
- package/src/objectStore/buckets/plugins.ts +0 -71
- package/src/objectStore/buckets/tests/app.spec.ts +0 -161
- package/src/objectStore/buckets/tests/global.spec.ts +0 -74
- package/src/objectStore/buckets/tests/plugins.spec.ts +0 -111
- package/src/objectStore/cloudfront.ts +0 -41
- package/src/objectStore/index.ts +0 -3
- package/src/objectStore/objectStore.ts +0 -585
- package/src/objectStore/utils.ts +0 -113
- package/src/platform/index.ts +0 -3
- package/src/platform/platformDb.ts +0 -6
- package/src/platform/tenants.ts +0 -101
- package/src/platform/tests/tenants.spec.ts +0 -26
- package/src/platform/users.ts +0 -129
- package/src/plugin/index.ts +0 -1
- package/src/plugin/tests/validation.spec.ts +0 -209
- package/src/plugin/utils.ts +0 -175
- package/src/queue/constants.ts +0 -8
- package/src/queue/inMemoryQueue.ts +0 -189
- package/src/queue/index.ts +0 -2
- package/src/queue/listeners.ts +0 -199
- package/src/queue/queue.ts +0 -84
- package/src/redis/index.ts +0 -6
- package/src/redis/init.ts +0 -118
- package/src/redis/redis.ts +0 -358
- package/src/redis/redlockImpl.ts +0 -155
- package/src/redis/tests/redis.spec.ts +0 -207
- package/src/redis/tests/redlockImpl.spec.ts +0 -105
- package/src/redis/utils.ts +0 -128
- package/src/security/auth.ts +0 -24
- package/src/security/encryption.ts +0 -185
- package/src/security/index.ts +0 -1
- package/src/security/permissions.ts +0 -166
- package/src/security/roles.ts +0 -655
- package/src/security/secrets.ts +0 -20
- package/src/security/sessions.ts +0 -123
- package/src/security/tests/auth.spec.ts +0 -45
- package/src/security/tests/encryption.spec.ts +0 -31
- package/src/security/tests/permissions.spec.ts +0 -146
- package/src/security/tests/secrets.spec.ts +0 -35
- package/src/security/tests/sessions.spec.ts +0 -12
- package/src/sql/designDoc.ts +0 -17
- package/src/sql/index.ts +0 -5
- package/src/sql/sql.ts +0 -1854
- package/src/sql/sqlTable.ts +0 -319
- package/src/sql/utils.ts +0 -193
- package/src/tenancy/db.ts +0 -6
- package/src/tenancy/index.ts +0 -2
- package/src/tenancy/tenancy.ts +0 -148
- package/src/tenancy/tests/tenancy.spec.ts +0 -184
- package/src/timers/index.ts +0 -1
- package/src/timers/timers.ts +0 -22
- package/src/users/db.ts +0 -582
- package/src/users/events.ts +0 -176
- package/src/users/index.ts +0 -4
- package/src/users/lookup.ts +0 -99
- package/src/users/test/db.spec.ts +0 -188
- package/src/users/test/utils.spec.ts +0 -67
- package/src/users/users.ts +0 -353
- package/src/users/utils.ts +0 -81
- package/src/utils/Duration.ts +0 -56
- package/src/utils/hashing.ts +0 -15
- package/src/utils/index.ts +0 -4
- package/src/utils/stringUtils.ts +0 -8
- package/src/utils/tests/Duration.spec.ts +0 -19
- package/src/utils/tests/utils.spec.ts +0 -204
- package/src/utils/utils.ts +0 -249
- package/tests/core/logging.ts +0 -34
- package/tests/core/users/users.spec.js +0 -53
- package/tests/core/utilities/index.ts +0 -7
- package/tests/core/utilities/jestUtils.ts +0 -33
- package/tests/core/utilities/mocks/alerts.ts +0 -4
- package/tests/core/utilities/mocks/date.ts +0 -3
- package/tests/core/utilities/mocks/events.ts +0 -132
- package/tests/core/utilities/mocks/index.ts +0 -9
- package/tests/core/utilities/mocks/licenses.ts +0 -119
- package/tests/core/utilities/queue.ts +0 -9
- package/tests/core/utilities/structures/Chance.ts +0 -20
- package/tests/core/utilities/structures/accounts.ts +0 -80
- package/tests/core/utilities/structures/apps.ts +0 -21
- package/tests/core/utilities/structures/common.ts +0 -7
- package/tests/core/utilities/structures/db.ts +0 -12
- package/tests/core/utilities/structures/documents/index.ts +0 -1
- package/tests/core/utilities/structures/documents/platform/index.ts +0 -1
- package/tests/core/utilities/structures/documents/platform/installation.ts +0 -12
- package/tests/core/utilities/structures/generator.ts +0 -3
- package/tests/core/utilities/structures/index.ts +0 -15
- package/tests/core/utilities/structures/koa.ts +0 -16
- package/tests/core/utilities/structures/licenses.ts +0 -190
- package/tests/core/utilities/structures/plugins.ts +0 -19
- package/tests/core/utilities/structures/quotas.ts +0 -72
- package/tests/core/utilities/structures/scim.ts +0 -80
- package/tests/core/utilities/structures/sso.ts +0 -118
- package/tests/core/utilities/structures/tenants.ts +0 -5
- package/tests/core/utilities/structures/userGroups.ts +0 -10
- package/tests/core/utilities/structures/users.ts +0 -89
- package/tests/core/utilities/testContainerUtils.ts +0 -165
- package/tests/core/utilities/utils/index.ts +0 -2
- package/tests/core/utilities/utils/queue.ts +0 -27
- package/tests/core/utilities/utils/time.ts +0 -3
- package/tests/extra/DBTestConfiguration.ts +0 -36
- package/tests/extra/index.ts +0 -2
- package/tests/extra/testEnv.ts +0 -95
- package/tests/index.ts +0 -2
- package/tests/jestEnv.ts +0 -10
- package/tests/jestSetup.ts +0 -36
package/src/security/roles.ts
DELETED
|
@@ -1,655 +0,0 @@
|
|
|
1
|
-
import semver from "semver"
|
|
2
|
-
import {
|
|
3
|
-
prefixRoleID,
|
|
4
|
-
getRoleParams,
|
|
5
|
-
DocumentType,
|
|
6
|
-
SEPARATOR,
|
|
7
|
-
doWithDB,
|
|
8
|
-
} from "../db"
|
|
9
|
-
import { getAppDB } from "../context"
|
|
10
|
-
import {
|
|
11
|
-
Screen,
|
|
12
|
-
Role as RoleDoc,
|
|
13
|
-
RoleUIMetadata,
|
|
14
|
-
Database,
|
|
15
|
-
App,
|
|
16
|
-
BuiltinPermissionID,
|
|
17
|
-
PermissionLevel,
|
|
18
|
-
} from "@budibase/types"
|
|
19
|
-
import cloneDeep from "lodash/fp/cloneDeep"
|
|
20
|
-
import { RoleColor, helpers } from "@budibase/shared-core"
|
|
21
|
-
import { uniqBy } from "lodash"
|
|
22
|
-
import { default as env } from "../environment"
|
|
23
|
-
|
|
24
|
-
export const BUILTIN_ROLE_IDS = {
|
|
25
|
-
ADMIN: "ADMIN",
|
|
26
|
-
POWER: "POWER",
|
|
27
|
-
BASIC: "BASIC",
|
|
28
|
-
PUBLIC: "PUBLIC",
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const BUILTIN_IDS = {
|
|
32
|
-
...BUILTIN_ROLE_IDS,
|
|
33
|
-
BUILDER: "BUILDER",
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export const RoleIDVersion = {
|
|
37
|
-
// original version, with a UUID based ID
|
|
38
|
-
UUID: undefined,
|
|
39
|
-
// new version - with name based ID
|
|
40
|
-
NAME: "name",
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
function rolesInList(roleIds: string[], ids: string | string[]) {
|
|
44
|
-
if (Array.isArray(ids)) {
|
|
45
|
-
return ids.filter(id => roleIds.includes(id)).length === ids.length
|
|
46
|
-
} else {
|
|
47
|
-
return roleIds.includes(ids)
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export class Role implements RoleDoc {
|
|
52
|
-
_id: string
|
|
53
|
-
_rev?: string
|
|
54
|
-
name: string
|
|
55
|
-
permissionId: BuiltinPermissionID
|
|
56
|
-
inherits?: string | string[]
|
|
57
|
-
version?: string
|
|
58
|
-
permissions: Record<string, PermissionLevel[]> = {}
|
|
59
|
-
uiMetadata?: RoleUIMetadata
|
|
60
|
-
|
|
61
|
-
constructor(
|
|
62
|
-
id: string,
|
|
63
|
-
name: string,
|
|
64
|
-
permissionId: BuiltinPermissionID,
|
|
65
|
-
uiMetadata?: RoleUIMetadata
|
|
66
|
-
) {
|
|
67
|
-
this._id = id
|
|
68
|
-
this.name = name
|
|
69
|
-
this.uiMetadata = uiMetadata
|
|
70
|
-
this.permissionId = permissionId
|
|
71
|
-
// version for managing the ID - removing the role_ when responding
|
|
72
|
-
this.version = RoleIDVersion.NAME
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
addInheritance(inherits?: string | string[]) {
|
|
76
|
-
// make sure IDs are correct format
|
|
77
|
-
if (inherits && typeof inherits === "string") {
|
|
78
|
-
inherits = prefixRoleIDNoBuiltin(inherits)
|
|
79
|
-
} else if (inherits && Array.isArray(inherits)) {
|
|
80
|
-
inherits = inherits.map(prefixRoleIDNoBuiltin)
|
|
81
|
-
}
|
|
82
|
-
this.inherits = inherits
|
|
83
|
-
return this
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
export class RoleHierarchyTraversal {
|
|
88
|
-
allRoles: RoleDoc[]
|
|
89
|
-
opts?: { defaultPublic?: boolean }
|
|
90
|
-
|
|
91
|
-
constructor(allRoles: RoleDoc[], opts?: { defaultPublic?: boolean }) {
|
|
92
|
-
this.allRoles = allRoles
|
|
93
|
-
this.opts = opts
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
walk(role: RoleDoc): RoleDoc[] {
|
|
97
|
-
const opts = this.opts,
|
|
98
|
-
allRoles = this.allRoles
|
|
99
|
-
// this will be a full walked list of roles - which may contain duplicates
|
|
100
|
-
let roleList: RoleDoc[] = []
|
|
101
|
-
if (!role || !role._id) {
|
|
102
|
-
return roleList
|
|
103
|
-
}
|
|
104
|
-
roleList.push(role)
|
|
105
|
-
if (Array.isArray(role.inherits)) {
|
|
106
|
-
for (let roleId of role.inherits) {
|
|
107
|
-
const foundRole = findRole(roleId, allRoles, opts)
|
|
108
|
-
if (foundRole) {
|
|
109
|
-
roleList = roleList.concat(this.walk(foundRole))
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
} else {
|
|
113
|
-
const foundRoleIds: string[] = []
|
|
114
|
-
let currentRole: RoleDoc | undefined = role
|
|
115
|
-
while (
|
|
116
|
-
currentRole &&
|
|
117
|
-
currentRole.inherits &&
|
|
118
|
-
!rolesInList(foundRoleIds, currentRole.inherits)
|
|
119
|
-
) {
|
|
120
|
-
if (Array.isArray(currentRole.inherits)) {
|
|
121
|
-
return roleList.concat(this.walk(currentRole))
|
|
122
|
-
} else {
|
|
123
|
-
foundRoleIds.push(currentRole.inherits)
|
|
124
|
-
currentRole = findRole(currentRole.inherits, allRoles, opts)
|
|
125
|
-
if (currentRole) {
|
|
126
|
-
roleList.push(currentRole)
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
// loop now found - stop iterating
|
|
130
|
-
if (helpers.roles.checkForRoleInheritanceLoops(roleList)) {
|
|
131
|
-
break
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
return uniqBy(roleList, role => role._id)
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
const BUILTIN_ROLES = {
|
|
140
|
-
ADMIN: new Role(
|
|
141
|
-
BUILTIN_IDS.ADMIN,
|
|
142
|
-
BUILTIN_IDS.ADMIN,
|
|
143
|
-
BuiltinPermissionID.ADMIN,
|
|
144
|
-
{
|
|
145
|
-
displayName: "App admin",
|
|
146
|
-
description: "Can do everything",
|
|
147
|
-
color: RoleColor.ADMIN,
|
|
148
|
-
}
|
|
149
|
-
).addInheritance(BUILTIN_IDS.POWER),
|
|
150
|
-
POWER: new Role(
|
|
151
|
-
BUILTIN_IDS.POWER,
|
|
152
|
-
BUILTIN_IDS.POWER,
|
|
153
|
-
BuiltinPermissionID.POWER,
|
|
154
|
-
{
|
|
155
|
-
displayName: "App power user",
|
|
156
|
-
description: "An app user with more access",
|
|
157
|
-
color: RoleColor.POWER,
|
|
158
|
-
}
|
|
159
|
-
).addInheritance(BUILTIN_IDS.BASIC),
|
|
160
|
-
BASIC: new Role(
|
|
161
|
-
BUILTIN_IDS.BASIC,
|
|
162
|
-
BUILTIN_IDS.BASIC,
|
|
163
|
-
BuiltinPermissionID.WRITE,
|
|
164
|
-
{
|
|
165
|
-
displayName: "App user",
|
|
166
|
-
description: "Any logged in user",
|
|
167
|
-
color: RoleColor.BASIC,
|
|
168
|
-
}
|
|
169
|
-
).addInheritance(BUILTIN_IDS.PUBLIC),
|
|
170
|
-
PUBLIC: new Role(
|
|
171
|
-
BUILTIN_IDS.PUBLIC,
|
|
172
|
-
BUILTIN_IDS.PUBLIC,
|
|
173
|
-
BuiltinPermissionID.PUBLIC,
|
|
174
|
-
{
|
|
175
|
-
displayName: "Public user",
|
|
176
|
-
description: "Accessible to anyone",
|
|
177
|
-
color: RoleColor.PUBLIC,
|
|
178
|
-
}
|
|
179
|
-
),
|
|
180
|
-
BUILDER: new Role(
|
|
181
|
-
BUILTIN_IDS.BUILDER,
|
|
182
|
-
BUILTIN_IDS.BUILDER,
|
|
183
|
-
BuiltinPermissionID.ADMIN,
|
|
184
|
-
{
|
|
185
|
-
displayName: "Builder user",
|
|
186
|
-
description: "Users that can edit this app",
|
|
187
|
-
color: RoleColor.BUILDER,
|
|
188
|
-
}
|
|
189
|
-
),
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
export function getBuiltinRoles(): { [key: string]: RoleDoc } {
|
|
193
|
-
return cloneDeep(BUILTIN_ROLES)
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
export function isBuiltin(role: string) {
|
|
197
|
-
return Object.values(BUILTIN_ROLE_IDS).includes(role)
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
export function prefixRoleIDNoBuiltin(roleId: string) {
|
|
201
|
-
if (isBuiltin(roleId)) {
|
|
202
|
-
return roleId
|
|
203
|
-
} else {
|
|
204
|
-
return prefixRoleID(roleId)
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
export function getBuiltinRole(roleId: string): Role | undefined {
|
|
209
|
-
const role = Object.values(BUILTIN_ROLES).find(role =>
|
|
210
|
-
roleId.includes(role._id)
|
|
211
|
-
)
|
|
212
|
-
if (!role) {
|
|
213
|
-
return undefined
|
|
214
|
-
}
|
|
215
|
-
return cloneDeep(role)
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
export function validInherits(
|
|
219
|
-
allRoles: RoleDoc[],
|
|
220
|
-
inherits?: string | string[]
|
|
221
|
-
): boolean {
|
|
222
|
-
if (!inherits) {
|
|
223
|
-
return false
|
|
224
|
-
}
|
|
225
|
-
const find = (id: string) => allRoles.find(r => roleIDsAreEqual(r._id!, id))
|
|
226
|
-
if (Array.isArray(inherits)) {
|
|
227
|
-
const filtered = inherits.filter(roleId => find(roleId))
|
|
228
|
-
return inherits.length !== 0 && filtered.length === inherits.length
|
|
229
|
-
} else {
|
|
230
|
-
return !!find(inherits)
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
/**
|
|
235
|
-
* Works through the inheritance ranks to see how far up the builtin stack this ID is.
|
|
236
|
-
*/
|
|
237
|
-
export function builtinRoleToNumber(id: string) {
|
|
238
|
-
const builtins = getBuiltinRoles()
|
|
239
|
-
const MAX = Object.values(builtins).length + 1
|
|
240
|
-
if (
|
|
241
|
-
roleIDsAreEqual(id, BUILTIN_IDS.ADMIN) ||
|
|
242
|
-
roleIDsAreEqual(id, BUILTIN_IDS.BUILDER)
|
|
243
|
-
) {
|
|
244
|
-
return MAX
|
|
245
|
-
}
|
|
246
|
-
let role = builtins[id],
|
|
247
|
-
count = 0
|
|
248
|
-
do {
|
|
249
|
-
if (!role) {
|
|
250
|
-
break
|
|
251
|
-
}
|
|
252
|
-
if (Array.isArray(role.inherits)) {
|
|
253
|
-
throw new Error("Built-in roles don't support multi-inheritance")
|
|
254
|
-
} else {
|
|
255
|
-
role = builtins[role.inherits!]
|
|
256
|
-
}
|
|
257
|
-
count++
|
|
258
|
-
} while (role !== null)
|
|
259
|
-
return count
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
/**
|
|
263
|
-
* Converts any role to a number, but has to be async to get the roles from db.
|
|
264
|
-
*/
|
|
265
|
-
export async function roleToNumber(id: string) {
|
|
266
|
-
if (isBuiltin(id)) {
|
|
267
|
-
return builtinRoleToNumber(id)
|
|
268
|
-
}
|
|
269
|
-
const hierarchy = (await getUserRoleHierarchy(id, {
|
|
270
|
-
defaultPublic: true,
|
|
271
|
-
})) as RoleDoc[]
|
|
272
|
-
const findNumber = (role: RoleDoc): number => {
|
|
273
|
-
if (!role.inherits) {
|
|
274
|
-
return 0
|
|
275
|
-
}
|
|
276
|
-
if (Array.isArray(role.inherits)) {
|
|
277
|
-
// find the built-in roles, get their number, sort it, then get the last one
|
|
278
|
-
const highestBuiltin: number | undefined = role.inherits
|
|
279
|
-
.map(roleId => {
|
|
280
|
-
const foundRole = hierarchy.find(role =>
|
|
281
|
-
roleIDsAreEqual(role._id!, roleId)
|
|
282
|
-
)
|
|
283
|
-
if (foundRole) {
|
|
284
|
-
return findNumber(foundRole) + 1
|
|
285
|
-
}
|
|
286
|
-
})
|
|
287
|
-
.filter(number => number)
|
|
288
|
-
.sort()
|
|
289
|
-
.pop()
|
|
290
|
-
if (highestBuiltin != undefined) {
|
|
291
|
-
return highestBuiltin
|
|
292
|
-
}
|
|
293
|
-
} else if (isBuiltin(role.inherits)) {
|
|
294
|
-
return builtinRoleToNumber(role.inherits) + 1
|
|
295
|
-
}
|
|
296
|
-
return 0
|
|
297
|
-
}
|
|
298
|
-
return Math.max(...hierarchy.map(findNumber))
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
/**
|
|
302
|
-
* Returns whichever builtin roleID is lower.
|
|
303
|
-
*/
|
|
304
|
-
export function lowerBuiltinRoleID(roleId1?: string, roleId2?: string): string {
|
|
305
|
-
if (!roleId1) {
|
|
306
|
-
return roleId2 as string
|
|
307
|
-
}
|
|
308
|
-
if (!roleId2) {
|
|
309
|
-
return roleId1 as string
|
|
310
|
-
}
|
|
311
|
-
return builtinRoleToNumber(roleId1) > builtinRoleToNumber(roleId2)
|
|
312
|
-
? roleId2
|
|
313
|
-
: roleId1
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
export function roleIDsAreEqual(roleId1: string, roleId2: string) {
|
|
317
|
-
// make sure both role IDs are prefixed correctly
|
|
318
|
-
return prefixRoleID(roleId1) === prefixRoleID(roleId2)
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
export function externalRole(role: RoleDoc): RoleDoc {
|
|
322
|
-
let _id: string | undefined
|
|
323
|
-
if (role._id) {
|
|
324
|
-
_id = getExternalRoleID(role._id)
|
|
325
|
-
}
|
|
326
|
-
return {
|
|
327
|
-
...role,
|
|
328
|
-
_id,
|
|
329
|
-
inherits: getExternalRoleIDs(role.inherits, role.version),
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
/**
|
|
334
|
-
* Given a list of roles, this will pick the role out, accounting for built ins.
|
|
335
|
-
*/
|
|
336
|
-
export function findRole(
|
|
337
|
-
roleId: string,
|
|
338
|
-
roles: RoleDoc[],
|
|
339
|
-
opts?: { defaultPublic?: boolean }
|
|
340
|
-
): RoleDoc | undefined {
|
|
341
|
-
// built in roles mostly come from the in-code implementation,
|
|
342
|
-
// but can be extended by a doc stored about them (e.g. permissions)
|
|
343
|
-
let role: RoleDoc | undefined = getBuiltinRole(roleId)
|
|
344
|
-
if (!role) {
|
|
345
|
-
// make sure has the prefix (if it has it then it won't be added)
|
|
346
|
-
roleId = prefixRoleID(roleId)
|
|
347
|
-
}
|
|
348
|
-
const dbRole = roles.find(
|
|
349
|
-
role => role._id && roleIDsAreEqual(role._id, roleId)
|
|
350
|
-
)
|
|
351
|
-
if (!dbRole && !isBuiltin(roleId) && opts?.defaultPublic) {
|
|
352
|
-
return cloneDeep(BUILTIN_ROLES.PUBLIC)
|
|
353
|
-
}
|
|
354
|
-
// combine the roles
|
|
355
|
-
role = Object.assign(role || {}, dbRole)
|
|
356
|
-
// finalise the ID
|
|
357
|
-
if (role?._id) {
|
|
358
|
-
role._id = getExternalRoleID(role._id, role.version)
|
|
359
|
-
}
|
|
360
|
-
return Object.keys(role).length === 0 ? undefined : role
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
/**
|
|
364
|
-
* Gets the role object, this is mainly useful for two purposes, to check if the level exists and
|
|
365
|
-
* to check if the role inherits any others.
|
|
366
|
-
* @param roleId The level ID to lookup.
|
|
367
|
-
* @param opts options for the function, like whether to halt errors, instead return public.
|
|
368
|
-
* @returns The role object, which may contain an "inherits" property.
|
|
369
|
-
*/
|
|
370
|
-
export async function getRole(
|
|
371
|
-
roleId: string,
|
|
372
|
-
opts?: { defaultPublic?: boolean }
|
|
373
|
-
): Promise<RoleDoc | undefined> {
|
|
374
|
-
const db = getAppDB()
|
|
375
|
-
const roleList = []
|
|
376
|
-
if (!isBuiltin(roleId)) {
|
|
377
|
-
const role = await db.tryGet<RoleDoc>(getDBRoleID(roleId))
|
|
378
|
-
if (role) {
|
|
379
|
-
roleList.push(role)
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
|
-
return findRole(roleId, roleList, opts)
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
export async function saveRoles(roles: RoleDoc[]) {
|
|
386
|
-
const db = getAppDB()
|
|
387
|
-
await db.bulkDocs(
|
|
388
|
-
roles
|
|
389
|
-
.filter(role => role._id)
|
|
390
|
-
.map(role => ({
|
|
391
|
-
...role,
|
|
392
|
-
_id: prefixRoleID(role._id!),
|
|
393
|
-
}))
|
|
394
|
-
)
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
/**
|
|
398
|
-
* Simple function to get all the roles based on the top level user role ID.
|
|
399
|
-
*/
|
|
400
|
-
async function getAllUserRoles(
|
|
401
|
-
userRoleId: string,
|
|
402
|
-
opts?: { defaultPublic?: boolean }
|
|
403
|
-
): Promise<RoleDoc[]> {
|
|
404
|
-
const allRoles = await getAllRoles()
|
|
405
|
-
// admins have access to all roles
|
|
406
|
-
if (roleIDsAreEqual(userRoleId, BUILTIN_IDS.ADMIN)) {
|
|
407
|
-
return allRoles
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
// get all the inherited roles
|
|
411
|
-
const foundRole = findRole(userRoleId, allRoles, opts)
|
|
412
|
-
let roles: RoleDoc[] = []
|
|
413
|
-
if (foundRole) {
|
|
414
|
-
const traversal = new RoleHierarchyTraversal(allRoles, opts)
|
|
415
|
-
roles = traversal.walk(foundRole)
|
|
416
|
-
}
|
|
417
|
-
return roles
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
export async function getUserRoleIdHierarchy(
|
|
421
|
-
userRoleId: string
|
|
422
|
-
): Promise<string[]> {
|
|
423
|
-
const roles = await getUserRoleHierarchy(userRoleId)
|
|
424
|
-
return roles.map(role => role._id!)
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
/**
|
|
428
|
-
* Returns an ordered array of the user's inherited role IDs, this can be used
|
|
429
|
-
* to determine if a user can access something that requires a specific role.
|
|
430
|
-
* @param userRoleId The user's role ID, this can be found in their access token.
|
|
431
|
-
* @param opts optional - if want to default to public use this.
|
|
432
|
-
* @returns returns an ordered array of the roles, with the first being their
|
|
433
|
-
* highest level of access and the last being the lowest level.
|
|
434
|
-
*/
|
|
435
|
-
export async function getUserRoleHierarchy(
|
|
436
|
-
userRoleId: string,
|
|
437
|
-
opts?: { defaultPublic?: boolean }
|
|
438
|
-
) {
|
|
439
|
-
// special case, if they don't have a role then they are a public user
|
|
440
|
-
return getAllUserRoles(userRoleId, opts)
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
// this function checks that the provided permissions are in an array format
|
|
444
|
-
// some templates/older apps will use a simple string instead of array for roles
|
|
445
|
-
// convert the string to an array using the theory that write is higher than read
|
|
446
|
-
export function checkForRoleResourceArray(
|
|
447
|
-
rolePerms: Record<string, PermissionLevel[]>,
|
|
448
|
-
resourceId: string
|
|
449
|
-
): Record<string, PermissionLevel[]> {
|
|
450
|
-
if (rolePerms && !Array.isArray(rolePerms[resourceId])) {
|
|
451
|
-
const permLevel = rolePerms[resourceId] as any
|
|
452
|
-
rolePerms[resourceId] = [permLevel]
|
|
453
|
-
if (permLevel === PermissionLevel.WRITE) {
|
|
454
|
-
rolePerms[resourceId].push(PermissionLevel.READ)
|
|
455
|
-
}
|
|
456
|
-
}
|
|
457
|
-
return rolePerms
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
export async function getAllRoleIds(appId: string): Promise<string[]> {
|
|
461
|
-
const roles = await getAllRoles(appId)
|
|
462
|
-
return roles.map(role => role._id!)
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
/**
|
|
466
|
-
* Given an app ID this will retrieve all of the roles that are currently within that app.
|
|
467
|
-
* @return An array of the role objects that were found.
|
|
468
|
-
*/
|
|
469
|
-
export async function getAllRoles(appId?: string): Promise<RoleDoc[]> {
|
|
470
|
-
if (appId) {
|
|
471
|
-
return doWithDB(appId, internal)
|
|
472
|
-
} else {
|
|
473
|
-
let appDB
|
|
474
|
-
try {
|
|
475
|
-
appDB = getAppDB()
|
|
476
|
-
} catch (error) {
|
|
477
|
-
// We don't have any apps, so we'll just use the built-in roles
|
|
478
|
-
}
|
|
479
|
-
return internal(appDB)
|
|
480
|
-
}
|
|
481
|
-
async function internal(db: Database | undefined) {
|
|
482
|
-
let roles: RoleDoc[] = []
|
|
483
|
-
if (db) {
|
|
484
|
-
const body = await db.allDocs(
|
|
485
|
-
getRoleParams(null, {
|
|
486
|
-
include_docs: true,
|
|
487
|
-
})
|
|
488
|
-
)
|
|
489
|
-
roles = body.rows.map((row: any) => row.doc)
|
|
490
|
-
roles.forEach(
|
|
491
|
-
role => (role._id = getExternalRoleID(role._id!, role.version))
|
|
492
|
-
)
|
|
493
|
-
}
|
|
494
|
-
const builtinRoles = getBuiltinRoles()
|
|
495
|
-
|
|
496
|
-
// exclude internal roles like builder
|
|
497
|
-
let externalBuiltinRoles = []
|
|
498
|
-
|
|
499
|
-
if (!db || (await shouldIncludePowerRole(db))) {
|
|
500
|
-
externalBuiltinRoles = [
|
|
501
|
-
BUILTIN_IDS.ADMIN,
|
|
502
|
-
BUILTIN_IDS.POWER,
|
|
503
|
-
BUILTIN_IDS.BASIC,
|
|
504
|
-
BUILTIN_IDS.PUBLIC,
|
|
505
|
-
]
|
|
506
|
-
} else {
|
|
507
|
-
externalBuiltinRoles = [
|
|
508
|
-
BUILTIN_IDS.ADMIN,
|
|
509
|
-
BUILTIN_IDS.BASIC,
|
|
510
|
-
BUILTIN_IDS.PUBLIC,
|
|
511
|
-
]
|
|
512
|
-
}
|
|
513
|
-
|
|
514
|
-
// need to combine builtin with any DB record of them (for sake of permissions)
|
|
515
|
-
for (let builtinRoleId of externalBuiltinRoles) {
|
|
516
|
-
const builtinRole = builtinRoles[builtinRoleId]
|
|
517
|
-
const dbBuiltin = roles.filter(dbRole =>
|
|
518
|
-
roleIDsAreEqual(dbRole._id!, builtinRoleId)
|
|
519
|
-
)[0]
|
|
520
|
-
if (dbBuiltin == null) {
|
|
521
|
-
roles.push(builtinRole || builtinRoles.BASIC)
|
|
522
|
-
} else {
|
|
523
|
-
// remove role and all back after combining with the builtin
|
|
524
|
-
roles = roles.filter(role => role._id !== dbBuiltin._id)
|
|
525
|
-
dbBuiltin._id = getExternalRoleID(builtinRole._id!, dbBuiltin.version)
|
|
526
|
-
roles.push({
|
|
527
|
-
...builtinRole,
|
|
528
|
-
...dbBuiltin,
|
|
529
|
-
name: builtinRole.name,
|
|
530
|
-
_id: getExternalRoleID(builtinRole._id!, builtinRole.version),
|
|
531
|
-
})
|
|
532
|
-
}
|
|
533
|
-
}
|
|
534
|
-
// check permissions
|
|
535
|
-
for (let role of roles) {
|
|
536
|
-
if (!role.permissions) {
|
|
537
|
-
continue
|
|
538
|
-
}
|
|
539
|
-
for (let resourceId of Object.keys(role.permissions)) {
|
|
540
|
-
role.permissions = checkForRoleResourceArray(
|
|
541
|
-
role.permissions,
|
|
542
|
-
resourceId
|
|
543
|
-
)
|
|
544
|
-
}
|
|
545
|
-
}
|
|
546
|
-
return roles
|
|
547
|
-
}
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
async function shouldIncludePowerRole(db: Database) {
|
|
551
|
-
const app = await db.tryGet<App>(DocumentType.APP_METADATA)
|
|
552
|
-
const creationVersion = app?.creationVersion
|
|
553
|
-
if (!creationVersion || !semver.valid(creationVersion)) {
|
|
554
|
-
// Old apps don't have creationVersion, so we should include it for backward compatibility
|
|
555
|
-
return true
|
|
556
|
-
}
|
|
557
|
-
|
|
558
|
-
const isGreaterThan3x = semver.gte(
|
|
559
|
-
creationVersion,
|
|
560
|
-
env.MIN_VERSION_WITHOUT_POWER_ROLE
|
|
561
|
-
)
|
|
562
|
-
return !isGreaterThan3x
|
|
563
|
-
}
|
|
564
|
-
|
|
565
|
-
export class AccessController {
|
|
566
|
-
userHierarchies: { [key: string]: string[] }
|
|
567
|
-
constructor() {
|
|
568
|
-
this.userHierarchies = {}
|
|
569
|
-
}
|
|
570
|
-
|
|
571
|
-
async hasAccess(tryingRoleId?: string, userRoleId?: string) {
|
|
572
|
-
// special cases, the screen has no role, the roles are the same or the user
|
|
573
|
-
// is currently in the builder
|
|
574
|
-
if (
|
|
575
|
-
tryingRoleId == null ||
|
|
576
|
-
tryingRoleId === "" ||
|
|
577
|
-
roleIDsAreEqual(tryingRoleId, BUILTIN_IDS.BUILDER) ||
|
|
578
|
-
roleIDsAreEqual(userRoleId!, tryingRoleId) ||
|
|
579
|
-
roleIDsAreEqual(userRoleId!, BUILTIN_IDS.BUILDER)
|
|
580
|
-
) {
|
|
581
|
-
return true
|
|
582
|
-
}
|
|
583
|
-
let roleIds = userRoleId ? this.userHierarchies[userRoleId] : null
|
|
584
|
-
if (!roleIds && userRoleId) {
|
|
585
|
-
roleIds = await getUserRoleIdHierarchy(userRoleId)
|
|
586
|
-
this.userHierarchies[userRoleId] = roleIds
|
|
587
|
-
}
|
|
588
|
-
|
|
589
|
-
return (
|
|
590
|
-
roleIds?.find(roleId => roleIDsAreEqual(roleId, tryingRoleId)) !==
|
|
591
|
-
undefined
|
|
592
|
-
)
|
|
593
|
-
}
|
|
594
|
-
|
|
595
|
-
async checkScreensAccess(screens: Screen[], userRoleId: string) {
|
|
596
|
-
let accessibleScreens = []
|
|
597
|
-
// don't want to handle this with Promise.all as this would mean all custom roles would be
|
|
598
|
-
// retrieved at same time, it is likely a custom role will be re-used and therefore want
|
|
599
|
-
// to work in sync for performance save
|
|
600
|
-
for (let screen of screens) {
|
|
601
|
-
const accessible = await this.checkScreenAccess(screen, userRoleId)
|
|
602
|
-
if (accessible) {
|
|
603
|
-
accessibleScreens.push(accessible)
|
|
604
|
-
}
|
|
605
|
-
}
|
|
606
|
-
return accessibleScreens
|
|
607
|
-
}
|
|
608
|
-
|
|
609
|
-
async checkScreenAccess(screen: Screen, userRoleId: string) {
|
|
610
|
-
const roleId = screen && screen.routing ? screen.routing.roleId : undefined
|
|
611
|
-
if (await this.hasAccess(roleId, userRoleId)) {
|
|
612
|
-
return screen
|
|
613
|
-
}
|
|
614
|
-
return null
|
|
615
|
-
}
|
|
616
|
-
}
|
|
617
|
-
|
|
618
|
-
/**
|
|
619
|
-
* Adds the "role_" for builtin role IDs which are to be written to the DB (for permissions).
|
|
620
|
-
*/
|
|
621
|
-
export function getDBRoleID(roleName: string) {
|
|
622
|
-
if (roleName?.startsWith(DocumentType.ROLE)) {
|
|
623
|
-
return roleName
|
|
624
|
-
}
|
|
625
|
-
return prefixRoleID(roleName)
|
|
626
|
-
}
|
|
627
|
-
|
|
628
|
-
/**
|
|
629
|
-
* Remove the "role_" from builtin role IDs that have been written to the DB (for permissions).
|
|
630
|
-
*/
|
|
631
|
-
export function getExternalRoleID(roleId: string, version?: string) {
|
|
632
|
-
// for built-in roles we want to remove the DB role ID element (role_)
|
|
633
|
-
if (
|
|
634
|
-
roleId.startsWith(`${DocumentType.ROLE}${SEPARATOR}`) &&
|
|
635
|
-
(isBuiltin(roleId) || version === RoleIDVersion.NAME)
|
|
636
|
-
) {
|
|
637
|
-
const parts = roleId.split(SEPARATOR)
|
|
638
|
-
parts.shift()
|
|
639
|
-
return parts.join(SEPARATOR)
|
|
640
|
-
}
|
|
641
|
-
return roleId
|
|
642
|
-
}
|
|
643
|
-
|
|
644
|
-
export function getExternalRoleIDs(
|
|
645
|
-
roleIds: string | string[] | undefined,
|
|
646
|
-
version?: string
|
|
647
|
-
) {
|
|
648
|
-
if (!roleIds) {
|
|
649
|
-
return roleIds
|
|
650
|
-
} else if (typeof roleIds === "string") {
|
|
651
|
-
return getExternalRoleID(roleIds, version)
|
|
652
|
-
} else {
|
|
653
|
-
return roleIds.map(roleId => getExternalRoleID(roleId, version))
|
|
654
|
-
}
|
|
655
|
-
}
|
package/src/security/secrets.ts
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import environment, { SECRETS } from "../environment"
|
|
2
|
-
|
|
3
|
-
export function stringContainsSecret(str: string) {
|
|
4
|
-
if (str.includes("-----BEGIN PRIVATE KEY-----")) {
|
|
5
|
-
return true
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
for (const key of SECRETS) {
|
|
9
|
-
const value = environment[key]
|
|
10
|
-
if (typeof value !== "string" || value === "") {
|
|
11
|
-
continue
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
if (str.includes(value)) {
|
|
15
|
-
return true
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
return false
|
|
20
|
-
}
|