@budibase/backend-core 2.9.19 → 2.9.21-alpha.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.
Files changed (250) hide show
  1. package/dist/index.js +266 -324
  2. package/dist/index.js.map +4 -4
  3. package/dist/index.js.meta.json +1 -1
  4. package/dist/package.json +19 -4
  5. package/dist/plugins.js +1 -1
  6. package/dist/plugins.js.map +1 -1
  7. package/dist/plugins.js.meta.json +1 -1
  8. package/dist/src/security/permissions.d.ts +1 -1
  9. package/dist/tests.js +222 -260
  10. package/dist/tests.js.map +4 -4
  11. package/dist/tests.js.meta.json +1 -1
  12. package/package.json +19 -4
  13. package/dist/tsconfig.build.tsbuildinfo +0 -1
  14. package/src/accounts/accounts.ts +0 -82
  15. package/src/accounts/api.ts +0 -59
  16. package/src/accounts/index.ts +0 -1
  17. package/src/auth/auth.ts +0 -208
  18. package/src/auth/index.ts +0 -1
  19. package/src/auth/tests/auth.spec.ts +0 -14
  20. package/src/blacklist/blacklist.ts +0 -54
  21. package/src/blacklist/index.ts +0 -1
  22. package/src/blacklist/tests/blacklist.spec.ts +0 -46
  23. package/src/cache/appMetadata.ts +0 -88
  24. package/src/cache/base/index.ts +0 -92
  25. package/src/cache/generic.ts +0 -30
  26. package/src/cache/index.ts +0 -5
  27. package/src/cache/tests/writethrough.spec.ts +0 -138
  28. package/src/cache/user.ts +0 -69
  29. package/src/cache/writethrough.ts +0 -133
  30. package/src/configs/configs.ts +0 -257
  31. package/src/configs/index.ts +0 -1
  32. package/src/configs/tests/configs.spec.ts +0 -184
  33. package/src/constants/db.ts +0 -63
  34. package/src/constants/index.ts +0 -2
  35. package/src/constants/misc.ts +0 -50
  36. package/src/context/Context.ts +0 -14
  37. package/src/context/identity.ts +0 -58
  38. package/src/context/index.ts +0 -3
  39. package/src/context/mainContext.ts +0 -310
  40. package/src/context/tests/index.spec.ts +0 -147
  41. package/src/context/types.ts +0 -11
  42. package/src/db/Replication.ts +0 -84
  43. package/src/db/constants.ts +0 -10
  44. package/src/db/couch/DatabaseImpl.ts +0 -238
  45. package/src/db/couch/connections.ts +0 -77
  46. package/src/db/couch/index.ts +0 -5
  47. package/src/db/couch/pouchDB.ts +0 -97
  48. package/src/db/couch/pouchDump.ts +0 -0
  49. package/src/db/couch/utils.ts +0 -50
  50. package/src/db/db.ts +0 -39
  51. package/src/db/errors.ts +0 -14
  52. package/src/db/index.ts +0 -12
  53. package/src/db/lucene.ts +0 -732
  54. package/src/db/searchIndexes/index.ts +0 -1
  55. package/src/db/searchIndexes/searchIndexes.ts +0 -62
  56. package/src/db/tests/index.spec.js +0 -25
  57. package/src/db/tests/lucene.spec.ts +0 -298
  58. package/src/db/tests/pouch.spec.js +0 -62
  59. package/src/db/tests/utils.spec.ts +0 -63
  60. package/src/db/utils.ts +0 -207
  61. package/src/db/views.ts +0 -241
  62. package/src/docIds/conversions.ts +0 -59
  63. package/src/docIds/ids.ts +0 -113
  64. package/src/docIds/index.ts +0 -2
  65. package/src/docIds/newid.ts +0 -5
  66. package/src/docIds/params.ts +0 -174
  67. package/src/docUpdates/index.ts +0 -29
  68. package/src/environment.ts +0 -201
  69. package/src/errors/errors.ts +0 -119
  70. package/src/errors/index.ts +0 -1
  71. package/src/events/analytics.ts +0 -6
  72. package/src/events/asyncEvents/index.ts +0 -2
  73. package/src/events/asyncEvents/publisher.ts +0 -12
  74. package/src/events/asyncEvents/queue.ts +0 -22
  75. package/src/events/backfill.ts +0 -183
  76. package/src/events/documentId.ts +0 -56
  77. package/src/events/events.ts +0 -40
  78. package/src/events/identification.ts +0 -310
  79. package/src/events/index.ts +0 -14
  80. package/src/events/processors/AnalyticsProcessor.ts +0 -64
  81. package/src/events/processors/AuditLogsProcessor.ts +0 -93
  82. package/src/events/processors/LoggingProcessor.ts +0 -37
  83. package/src/events/processors/Processors.ts +0 -52
  84. package/src/events/processors/async/DocumentUpdateProcessor.ts +0 -43
  85. package/src/events/processors/index.ts +0 -19
  86. package/src/events/processors/posthog/PosthogProcessor.ts +0 -118
  87. package/src/events/processors/posthog/index.ts +0 -2
  88. package/src/events/processors/posthog/rateLimiting.ts +0 -106
  89. package/src/events/processors/posthog/tests/PosthogProcessor.spec.ts +0 -168
  90. package/src/events/processors/types.ts +0 -1
  91. package/src/events/publishers/account.ts +0 -35
  92. package/src/events/publishers/app.ts +0 -155
  93. package/src/events/publishers/auditLog.ts +0 -26
  94. package/src/events/publishers/auth.ts +0 -73
  95. package/src/events/publishers/automation.ts +0 -110
  96. package/src/events/publishers/backfill.ts +0 -74
  97. package/src/events/publishers/backup.ts +0 -42
  98. package/src/events/publishers/datasource.ts +0 -48
  99. package/src/events/publishers/email.ts +0 -17
  100. package/src/events/publishers/environmentVariable.ts +0 -38
  101. package/src/events/publishers/group.ts +0 -99
  102. package/src/events/publishers/index.ts +0 -24
  103. package/src/events/publishers/installation.ts +0 -38
  104. package/src/events/publishers/layout.ts +0 -26
  105. package/src/events/publishers/license.ts +0 -84
  106. package/src/events/publishers/org.ts +0 -37
  107. package/src/events/publishers/plugin.ts +0 -47
  108. package/src/events/publishers/query.ts +0 -88
  109. package/src/events/publishers/role.ts +0 -62
  110. package/src/events/publishers/rows.ts +0 -29
  111. package/src/events/publishers/screen.ts +0 -36
  112. package/src/events/publishers/serve.ts +0 -43
  113. package/src/events/publishers/table.ts +0 -70
  114. package/src/events/publishers/user.ts +0 -202
  115. package/src/events/publishers/view.ts +0 -107
  116. package/src/featureFlags/index.ts +0 -77
  117. package/src/featureFlags/tests/featureFlags.spec.ts +0 -85
  118. package/src/helpers.ts +0 -9
  119. package/src/index.ts +0 -53
  120. package/src/installation.ts +0 -107
  121. package/src/logging/alerts.ts +0 -26
  122. package/src/logging/correlation/correlation.ts +0 -13
  123. package/src/logging/correlation/index.ts +0 -1
  124. package/src/logging/correlation/middleware.ts +0 -17
  125. package/src/logging/index.ts +0 -4
  126. package/src/logging/pino/logger.ts +0 -232
  127. package/src/logging/pino/middleware.ts +0 -45
  128. package/src/logging/system.ts +0 -81
  129. package/src/logging/tests/system.spec.ts +0 -61
  130. package/src/middleware/adminOnly.ts +0 -9
  131. package/src/middleware/auditLog.ts +0 -6
  132. package/src/middleware/authenticated.ts +0 -193
  133. package/src/middleware/builderOnly.ts +0 -20
  134. package/src/middleware/builderOrAdmin.ts +0 -20
  135. package/src/middleware/csrf.ts +0 -81
  136. package/src/middleware/errorHandling.ts +0 -29
  137. package/src/middleware/index.ts +0 -21
  138. package/src/middleware/internalApi.ts +0 -23
  139. package/src/middleware/joi-validator.ts +0 -45
  140. package/src/middleware/matchers.ts +0 -47
  141. package/src/middleware/passport/datasource/google.ts +0 -95
  142. package/src/middleware/passport/local.ts +0 -54
  143. package/src/middleware/passport/sso/google.ts +0 -77
  144. package/src/middleware/passport/sso/oidc.ts +0 -154
  145. package/src/middleware/passport/sso/sso.ts +0 -165
  146. package/src/middleware/passport/sso/tests/google.spec.ts +0 -67
  147. package/src/middleware/passport/sso/tests/oidc.spec.ts +0 -152
  148. package/src/middleware/passport/sso/tests/sso.spec.ts +0 -197
  149. package/src/middleware/passport/utils.ts +0 -38
  150. package/src/middleware/querystringToBody.ts +0 -28
  151. package/src/middleware/tenancy.ts +0 -36
  152. package/src/middleware/tests/builder.spec.ts +0 -180
  153. package/src/middleware/tests/matchers.spec.ts +0 -134
  154. package/src/migrations/definitions.ts +0 -40
  155. package/src/migrations/index.ts +0 -2
  156. package/src/migrations/migrations.ts +0 -191
  157. package/src/migrations/tests/__snapshots__/migrations.spec.ts.snap +0 -11
  158. package/src/migrations/tests/migrations.spec.ts +0 -64
  159. package/src/objectStore/buckets/app.ts +0 -40
  160. package/src/objectStore/buckets/global.ts +0 -29
  161. package/src/objectStore/buckets/index.ts +0 -3
  162. package/src/objectStore/buckets/plugins.ts +0 -71
  163. package/src/objectStore/buckets/tests/app.spec.ts +0 -171
  164. package/src/objectStore/buckets/tests/global.spec.ts +0 -74
  165. package/src/objectStore/buckets/tests/plugins.spec.ts +0 -111
  166. package/src/objectStore/cloudfront.ts +0 -41
  167. package/src/objectStore/index.ts +0 -3
  168. package/src/objectStore/objectStore.ts +0 -440
  169. package/src/objectStore/utils.ts +0 -27
  170. package/src/platform/index.ts +0 -3
  171. package/src/platform/platformDb.ts +0 -6
  172. package/src/platform/tenants.ts +0 -101
  173. package/src/platform/tests/tenants.spec.ts +0 -26
  174. package/src/platform/users.ts +0 -90
  175. package/src/plugin/index.ts +0 -1
  176. package/src/plugin/tests/validation.spec.ts +0 -83
  177. package/src/plugin/utils.ts +0 -156
  178. package/src/queue/constants.ts +0 -6
  179. package/src/queue/inMemoryQueue.ts +0 -141
  180. package/src/queue/index.ts +0 -2
  181. package/src/queue/listeners.ts +0 -195
  182. package/src/queue/queue.ts +0 -54
  183. package/src/redis/index.ts +0 -6
  184. package/src/redis/init.ts +0 -86
  185. package/src/redis/redis.ts +0 -308
  186. package/src/redis/redlockImpl.ts +0 -139
  187. package/src/redis/utils.ts +0 -117
  188. package/src/security/encryption.ts +0 -179
  189. package/src/security/permissions.ts +0 -159
  190. package/src/security/roles.ts +0 -420
  191. package/src/security/sessions.ts +0 -120
  192. package/src/security/tests/encryption.spec.ts +0 -31
  193. package/src/security/tests/permissions.spec.ts +0 -145
  194. package/src/security/tests/sessions.spec.ts +0 -12
  195. package/src/tenancy/db.ts +0 -6
  196. package/src/tenancy/index.ts +0 -2
  197. package/src/tenancy/tenancy.ts +0 -140
  198. package/src/tenancy/tests/tenancy.spec.ts +0 -184
  199. package/src/timers/index.ts +0 -1
  200. package/src/timers/timers.ts +0 -22
  201. package/src/users/db.ts +0 -460
  202. package/src/users/events.ts +0 -176
  203. package/src/users/index.ts +0 -4
  204. package/src/users/lookup.ts +0 -102
  205. package/src/users/users.ts +0 -276
  206. package/src/users/utils.ts +0 -55
  207. package/src/utils/hashing.ts +0 -14
  208. package/src/utils/index.ts +0 -3
  209. package/src/utils/stringUtils.ts +0 -8
  210. package/src/utils/tests/utils.spec.ts +0 -191
  211. package/src/utils/utils.ts +0 -239
  212. package/tests/core/logging.ts +0 -34
  213. package/tests/core/utilities/index.ts +0 -6
  214. package/tests/core/utilities/jestUtils.ts +0 -30
  215. package/tests/core/utilities/mocks/alerts.ts +0 -3
  216. package/tests/core/utilities/mocks/date.ts +0 -2
  217. package/tests/core/utilities/mocks/events.ts +0 -131
  218. package/tests/core/utilities/mocks/fetch.ts +0 -17
  219. package/tests/core/utilities/mocks/index.ts +0 -10
  220. package/tests/core/utilities/mocks/licenses.ts +0 -107
  221. package/tests/core/utilities/mocks/posthog.ts +0 -7
  222. package/tests/core/utilities/structures/Chance.ts +0 -20
  223. package/tests/core/utilities/structures/accounts.ts +0 -115
  224. package/tests/core/utilities/structures/apps.ts +0 -21
  225. package/tests/core/utilities/structures/common.ts +0 -7
  226. package/tests/core/utilities/structures/db.ts +0 -12
  227. package/tests/core/utilities/structures/documents/index.ts +0 -1
  228. package/tests/core/utilities/structures/documents/platform/index.ts +0 -1
  229. package/tests/core/utilities/structures/documents/platform/installation.ts +0 -12
  230. package/tests/core/utilities/structures/generator.ts +0 -2
  231. package/tests/core/utilities/structures/index.ts +0 -15
  232. package/tests/core/utilities/structures/koa.ts +0 -16
  233. package/tests/core/utilities/structures/licenses.ts +0 -167
  234. package/tests/core/utilities/structures/plugins.ts +0 -19
  235. package/tests/core/utilities/structures/quotas.ts +0 -67
  236. package/tests/core/utilities/structures/scim.ts +0 -80
  237. package/tests/core/utilities/structures/shared.ts +0 -19
  238. package/tests/core/utilities/structures/sso.ts +0 -119
  239. package/tests/core/utilities/structures/tenants.ts +0 -5
  240. package/tests/core/utilities/structures/userGroups.ts +0 -10
  241. package/tests/core/utilities/structures/users.ts +0 -73
  242. package/tests/core/utilities/testContainerUtils.ts +0 -98
  243. package/tests/core/utilities/utils/index.ts +0 -1
  244. package/tests/core/utilities/utils/time.ts +0 -3
  245. package/tests/extra/DBTestConfiguration.ts +0 -36
  246. package/tests/extra/index.ts +0 -2
  247. package/tests/extra/testEnv.ts +0 -95
  248. package/tests/index.ts +0 -1
  249. package/tests/jestEnv.ts +0 -6
  250. package/tests/jestSetup.ts +0 -28
@@ -1,420 +0,0 @@
1
- import { BuiltinPermissionID, PermissionLevel } from "./permissions"
2
- import { prefixRoleID, getRoleParams, DocumentType, SEPARATOR } from "../db"
3
- import { getAppDB } from "../context"
4
- import { doWithDB } from "../db"
5
- import { Screen, Role as RoleDoc } from "@budibase/types"
6
- import cloneDeep from "lodash/fp/cloneDeep"
7
-
8
- export const BUILTIN_ROLE_IDS = {
9
- ADMIN: "ADMIN",
10
- POWER: "POWER",
11
- BASIC: "BASIC",
12
- PUBLIC: "PUBLIC",
13
- }
14
-
15
- const BUILTIN_IDS = {
16
- ...BUILTIN_ROLE_IDS,
17
- BUILDER: "BUILDER",
18
- }
19
-
20
- // exclude internal roles like builder
21
- const EXTERNAL_BUILTIN_ROLE_IDS = [
22
- BUILTIN_IDS.ADMIN,
23
- BUILTIN_IDS.POWER,
24
- BUILTIN_IDS.BASIC,
25
- BUILTIN_IDS.PUBLIC,
26
- ]
27
-
28
- export const RoleIDVersion = {
29
- // original version, with a UUID based ID
30
- UUID: undefined,
31
- // new version - with name based ID
32
- NAME: "name",
33
- }
34
-
35
- export class Role implements RoleDoc {
36
- _id: string
37
- _rev?: string
38
- name: string
39
- permissionId: string
40
- inherits?: string
41
- version?: string
42
- permissions = {}
43
-
44
- constructor(id: string, name: string, permissionId: string) {
45
- this._id = id
46
- this.name = name
47
- this.permissionId = permissionId
48
- // version for managing the ID - removing the role_ when responding
49
- this.version = RoleIDVersion.NAME
50
- }
51
-
52
- addInheritance(inherits: string) {
53
- this.inherits = inherits
54
- return this
55
- }
56
- }
57
-
58
- const BUILTIN_ROLES = {
59
- ADMIN: new Role(
60
- BUILTIN_IDS.ADMIN,
61
- "Admin",
62
- BuiltinPermissionID.ADMIN
63
- ).addInheritance(BUILTIN_IDS.POWER),
64
- POWER: new Role(
65
- BUILTIN_IDS.POWER,
66
- "Power",
67
- BuiltinPermissionID.POWER
68
- ).addInheritance(BUILTIN_IDS.BASIC),
69
- BASIC: new Role(
70
- BUILTIN_IDS.BASIC,
71
- "Basic",
72
- BuiltinPermissionID.WRITE
73
- ).addInheritance(BUILTIN_IDS.PUBLIC),
74
- PUBLIC: new Role(BUILTIN_IDS.PUBLIC, "Public", BuiltinPermissionID.PUBLIC),
75
- BUILDER: new Role(BUILTIN_IDS.BUILDER, "Builder", BuiltinPermissionID.ADMIN),
76
- }
77
-
78
- export function getBuiltinRoles(): { [key: string]: RoleDoc } {
79
- return cloneDeep(BUILTIN_ROLES)
80
- }
81
-
82
- export const BUILTIN_ROLE_ID_ARRAY = Object.values(BUILTIN_ROLES).map(
83
- role => role._id
84
- )
85
-
86
- export const BUILTIN_ROLE_NAME_ARRAY = Object.values(BUILTIN_ROLES).map(
87
- role => role.name
88
- )
89
-
90
- export function isBuiltin(role?: string) {
91
- return BUILTIN_ROLE_ID_ARRAY.some(builtin => role?.includes(builtin))
92
- }
93
-
94
- /**
95
- * Works through the inheritance ranks to see how far up the builtin stack this ID is.
96
- */
97
- export function builtinRoleToNumber(id?: string) {
98
- if (!id) {
99
- return 0
100
- }
101
- const builtins = getBuiltinRoles()
102
- const MAX = Object.values(builtins).length + 1
103
- if (id === BUILTIN_IDS.ADMIN || id === BUILTIN_IDS.BUILDER) {
104
- return MAX
105
- }
106
- let role = builtins[id],
107
- count = 0
108
- do {
109
- if (!role) {
110
- break
111
- }
112
- role = builtins[role.inherits!]
113
- count++
114
- } while (role !== null)
115
- return count
116
- }
117
-
118
- /**
119
- * Converts any role to a number, but has to be async to get the roles from db.
120
- */
121
- export async function roleToNumber(id?: string) {
122
- if (isBuiltin(id)) {
123
- return builtinRoleToNumber(id)
124
- }
125
- const hierarchy = (await getUserRoleHierarchy(id)) as RoleDoc[]
126
- for (let role of hierarchy) {
127
- if (isBuiltin(role?.inherits)) {
128
- return builtinRoleToNumber(role.inherits) + 1
129
- }
130
- }
131
- return 0
132
- }
133
-
134
- /**
135
- * Returns whichever builtin roleID is lower.
136
- */
137
- export function lowerBuiltinRoleID(roleId1?: string, roleId2?: string): string {
138
- if (!roleId1) {
139
- return roleId2 as string
140
- }
141
- if (!roleId2) {
142
- return roleId1 as string
143
- }
144
- return builtinRoleToNumber(roleId1) > builtinRoleToNumber(roleId2)
145
- ? roleId2
146
- : roleId1
147
- }
148
-
149
- /**
150
- * Gets the role object, this is mainly useful for two purposes, to check if the level exists and
151
- * to check if the role inherits any others.
152
- * @param {string|null} roleId The level ID to lookup.
153
- * @param {object|null} opts options for the function, like whether to halt errors, instead return public.
154
- * @returns {Promise<Role|object|null>} The role object, which may contain an "inherits" property.
155
- */
156
- export async function getRole(
157
- roleId?: string,
158
- opts?: { defaultPublic?: boolean }
159
- ): Promise<RoleDoc | undefined> {
160
- if (!roleId) {
161
- return undefined
162
- }
163
- let role: any = {}
164
- // built in roles mostly come from the in-code implementation,
165
- // but can be extended by a doc stored about them (e.g. permissions)
166
- if (isBuiltin(roleId)) {
167
- role = cloneDeep(
168
- Object.values(BUILTIN_ROLES).find(role => role._id === roleId)
169
- )
170
- } else {
171
- // make sure has the prefix (if it has it then it won't be added)
172
- roleId = prefixRoleID(roleId)
173
- }
174
- try {
175
- const db = getAppDB()
176
- const dbRole = await db.get(getDBRoleID(roleId))
177
- role = Object.assign(role, dbRole)
178
- // finalise the ID
179
- role._id = getExternalRoleID(role._id, role.version)
180
- } catch (err) {
181
- if (!isBuiltin(roleId) && opts?.defaultPublic) {
182
- return cloneDeep(BUILTIN_ROLES.PUBLIC)
183
- }
184
- // only throw an error if there is no role at all
185
- if (Object.keys(role).length === 0) {
186
- throw err
187
- }
188
- }
189
- return role
190
- }
191
-
192
- /**
193
- * Simple function to get all the roles based on the top level user role ID.
194
- */
195
- async function getAllUserRoles(userRoleId?: string): Promise<RoleDoc[]> {
196
- // admins have access to all roles
197
- if (userRoleId === BUILTIN_IDS.ADMIN) {
198
- return getAllRoles()
199
- }
200
- let currentRole = await getRole(userRoleId)
201
- let roles = currentRole ? [currentRole] : []
202
- let roleIds = [userRoleId]
203
- // get all the inherited roles
204
- while (
205
- currentRole &&
206
- currentRole.inherits &&
207
- roleIds.indexOf(currentRole.inherits) === -1
208
- ) {
209
- roleIds.push(currentRole.inherits)
210
- currentRole = await getRole(currentRole.inherits)
211
- if (currentRole) {
212
- roles.push(currentRole)
213
- }
214
- }
215
- return roles
216
- }
217
-
218
- /**
219
- * Returns an ordered array of the user's inherited role IDs, this can be used
220
- * to determine if a user can access something that requires a specific role.
221
- * @param {string} userRoleId The user's role ID, this can be found in their access token.
222
- * @param {object} opts Various options, such as whether to only retrieve the IDs (default true).
223
- * @returns {Promise<string[]|object[]>} returns an ordered array of the roles, with the first being their
224
- * highest level of access and the last being the lowest level.
225
- */
226
- export async function getUserRoleHierarchy(
227
- userRoleId?: string,
228
- opts = { idOnly: true }
229
- ) {
230
- // special case, if they don't have a role then they are a public user
231
- const roles = await getAllUserRoles(userRoleId)
232
- return opts.idOnly ? roles.map(role => role._id) : roles
233
- }
234
-
235
- // this function checks that the provided permissions are in an array format
236
- // some templates/older apps will use a simple string instead of array for roles
237
- // convert the string to an array using the theory that write is higher than read
238
- export function checkForRoleResourceArray(
239
- rolePerms: { [key: string]: string[] },
240
- resourceId: string
241
- ) {
242
- if (rolePerms && !Array.isArray(rolePerms[resourceId])) {
243
- const permLevel = rolePerms[resourceId] as any
244
- rolePerms[resourceId] = [permLevel]
245
- if (permLevel === PermissionLevel.WRITE) {
246
- rolePerms[resourceId].push(PermissionLevel.READ)
247
- }
248
- }
249
- return rolePerms
250
- }
251
-
252
- /**
253
- * Given an app ID this will retrieve all of the roles that are currently within that app.
254
- * @return {Promise<object[]>} An array of the role objects that were found.
255
- */
256
- export async function getAllRoles(appId?: string) {
257
- if (appId) {
258
- return doWithDB(appId, internal)
259
- } else {
260
- let appDB
261
- try {
262
- appDB = getAppDB()
263
- } catch (error) {
264
- // We don't have any apps, so we'll just use the built-in roles
265
- }
266
- return internal(appDB)
267
- }
268
- async function internal(db: any) {
269
- let roles: RoleDoc[] = []
270
- if (db) {
271
- const body = await db.allDocs(
272
- getRoleParams(null, {
273
- include_docs: true,
274
- })
275
- )
276
- roles = body.rows.map((row: any) => row.doc)
277
- roles.forEach(
278
- role => (role._id = getExternalRoleID(role._id!, role.version))
279
- )
280
- }
281
- const builtinRoles = getBuiltinRoles()
282
-
283
- // need to combine builtin with any DB record of them (for sake of permissions)
284
- for (let builtinRoleId of EXTERNAL_BUILTIN_ROLE_IDS) {
285
- const builtinRole = builtinRoles[builtinRoleId]
286
- const dbBuiltin = roles.filter(
287
- dbRole =>
288
- getExternalRoleID(dbRole._id!, dbRole.version) === builtinRoleId
289
- )[0]
290
- if (dbBuiltin == null) {
291
- roles.push(builtinRole || builtinRoles.BASIC)
292
- } else {
293
- // remove role and all back after combining with the builtin
294
- roles = roles.filter(role => role._id !== dbBuiltin._id)
295
- dbBuiltin._id = getExternalRoleID(dbBuiltin._id!, dbBuiltin.version)
296
- roles.push(Object.assign(builtinRole, dbBuiltin))
297
- }
298
- }
299
- // check permissions
300
- for (let role of roles) {
301
- if (!role.permissions) {
302
- continue
303
- }
304
- for (let resourceId of Object.keys(role.permissions)) {
305
- role.permissions = checkForRoleResourceArray(
306
- role.permissions,
307
- resourceId
308
- )
309
- }
310
- }
311
- return roles
312
- }
313
- }
314
-
315
- /**
316
- * This retrieves the required role for a resource
317
- * @param permLevel The level of request
318
- * @param resourceId The resource being requested
319
- * @param subResourceId The sub resource being requested
320
- * @return {Promise<{permissions}|Object>} returns the permissions required to access.
321
- */
322
- export async function getRequiredResourceRole(
323
- permLevel: string,
324
- { resourceId, subResourceId }: { resourceId?: string; subResourceId?: string }
325
- ) {
326
- const roles = await getAllRoles()
327
- let main = [],
328
- sub = []
329
- for (let role of roles) {
330
- // no permissions, ignore it
331
- if (!role.permissions) {
332
- continue
333
- }
334
- const mainRes = resourceId ? role.permissions[resourceId] : undefined
335
- const subRes = subResourceId ? role.permissions[subResourceId] : undefined
336
- if (mainRes && mainRes.indexOf(permLevel) !== -1) {
337
- main.push(role._id)
338
- } else if (subRes && subRes.indexOf(permLevel) !== -1) {
339
- sub.push(role._id)
340
- }
341
- }
342
- // for now just return the IDs
343
- return main.concat(sub)
344
- }
345
-
346
- export class AccessController {
347
- userHierarchies: { [key: string]: string[] }
348
- constructor() {
349
- this.userHierarchies = {}
350
- }
351
-
352
- async hasAccess(tryingRoleId?: string, userRoleId?: string) {
353
- // special cases, the screen has no role, the roles are the same or the user
354
- // is currently in the builder
355
- if (
356
- tryingRoleId == null ||
357
- tryingRoleId === "" ||
358
- tryingRoleId === userRoleId ||
359
- tryingRoleId === BUILTIN_IDS.BUILDER ||
360
- userRoleId === BUILTIN_IDS.BUILDER
361
- ) {
362
- return true
363
- }
364
- let roleIds = userRoleId ? this.userHierarchies[userRoleId] : null
365
- if (!roleIds && userRoleId) {
366
- roleIds = (await getUserRoleHierarchy(userRoleId, {
367
- idOnly: true,
368
- })) as string[]
369
- this.userHierarchies[userRoleId] = roleIds
370
- }
371
-
372
- return roleIds?.indexOf(tryingRoleId) !== -1
373
- }
374
-
375
- async checkScreensAccess(screens: Screen[], userRoleId: string) {
376
- let accessibleScreens = []
377
- // don't want to handle this with Promise.all as this would mean all custom roles would be
378
- // retrieved at same time, it is likely a custom role will be re-used and therefore want
379
- // to work in sync for performance save
380
- for (let screen of screens) {
381
- const accessible = await this.checkScreenAccess(screen, userRoleId)
382
- if (accessible) {
383
- accessibleScreens.push(accessible)
384
- }
385
- }
386
- return accessibleScreens
387
- }
388
-
389
- async checkScreenAccess(screen: Screen, userRoleId: string) {
390
- const roleId = screen && screen.routing ? screen.routing.roleId : undefined
391
- if (await this.hasAccess(roleId, userRoleId)) {
392
- return screen
393
- }
394
- return null
395
- }
396
- }
397
-
398
- /**
399
- * Adds the "role_" for builtin role IDs which are to be written to the DB (for permissions).
400
- */
401
- export function getDBRoleID(roleName: string) {
402
- if (roleName?.startsWith(DocumentType.ROLE)) {
403
- return roleName
404
- }
405
- return prefixRoleID(roleName)
406
- }
407
-
408
- /**
409
- * Remove the "role_" from builtin role IDs that have been written to the DB (for permissions).
410
- */
411
- export function getExternalRoleID(roleId: string, version?: string) {
412
- // for built-in roles we want to remove the DB role ID element (role_)
413
- if (
414
- (roleId.startsWith(DocumentType.ROLE) && isBuiltin(roleId)) ||
415
- version === RoleIDVersion.NAME
416
- ) {
417
- return roleId.split(`${DocumentType.ROLE}${SEPARATOR}`)[1]
418
- }
419
- return roleId
420
- }
@@ -1,120 +0,0 @@
1
- const redis = require("../redis/init")
2
- const { v4: uuidv4 } = require("uuid")
3
- const { logWarn } = require("../logging")
4
- import env from "../environment"
5
- import {
6
- Session,
7
- ScannedSession,
8
- SessionKey,
9
- CreateSession,
10
- } from "@budibase/types"
11
-
12
- // a week in seconds
13
- const EXPIRY_SECONDS = 86400 * 7
14
-
15
- function makeSessionID(userId: string, sessionId: string) {
16
- return `${userId}/${sessionId}`
17
- }
18
-
19
- export async function getSessionsForUser(userId: string): Promise<Session[]> {
20
- if (!userId) {
21
- console.trace("Cannot get sessions for undefined userId")
22
- return []
23
- }
24
- const client = await redis.getSessionClient()
25
- const sessions: ScannedSession[] = await client.scan(userId)
26
- return sessions.map(session => session.value)
27
- }
28
-
29
- export async function invalidateSessions(
30
- userId: string,
31
- opts: { sessionIds?: string[]; reason?: string } = {}
32
- ) {
33
- try {
34
- const reason = opts?.reason || "unknown"
35
- let sessionIds: string[] = opts.sessionIds || []
36
- let sessionKeys: SessionKey[]
37
-
38
- // If no sessionIds, get all the sessions for the user
39
- if (sessionIds.length === 0) {
40
- const sessions = await getSessionsForUser(userId)
41
- sessionKeys = sessions.map(session => ({
42
- key: makeSessionID(session.userId, session.sessionId),
43
- }))
44
- } else {
45
- // use the passed array of sessionIds
46
- sessionIds = Array.isArray(sessionIds) ? sessionIds : [sessionIds]
47
- sessionKeys = sessionIds.map(sessionId => ({
48
- key: makeSessionID(userId, sessionId),
49
- }))
50
- }
51
-
52
- if (sessionKeys && sessionKeys.length > 0) {
53
- const client = await redis.getSessionClient()
54
- const promises = []
55
- for (let sessionKey of sessionKeys) {
56
- promises.push(client.delete(sessionKey.key))
57
- }
58
- if (!env.isTest()) {
59
- logWarn(
60
- `Invalidating sessions for ${userId} (reason: ${reason}) - ${sessionKeys
61
- .map(sessionKey => sessionKey.key)
62
- .join(", ")}`
63
- )
64
- }
65
- await Promise.all(promises)
66
- }
67
- } catch (err) {
68
- console.error(`Error invalidating sessions: ${err}`)
69
- }
70
- }
71
-
72
- export async function createASession(
73
- userId: string,
74
- createSession: CreateSession
75
- ) {
76
- // invalidate all other sessions
77
- await invalidateSessions(userId, { reason: "creation" })
78
-
79
- const client = await redis.getSessionClient()
80
- const sessionId = createSession.sessionId
81
- const csrfToken = createSession.csrfToken ? createSession.csrfToken : uuidv4()
82
- const key = makeSessionID(userId, sessionId)
83
-
84
- const session: Session = {
85
- ...createSession,
86
- csrfToken,
87
- createdAt: new Date().toISOString(),
88
- lastAccessedAt: new Date().toISOString(),
89
- userId,
90
- }
91
- await client.store(key, session, EXPIRY_SECONDS)
92
- return session
93
- }
94
-
95
- export async function updateSessionTTL(session: Session) {
96
- const client = await redis.getSessionClient()
97
- const key = makeSessionID(session.userId, session.sessionId)
98
- session.lastAccessedAt = new Date().toISOString()
99
- await client.store(key, session, EXPIRY_SECONDS)
100
- }
101
-
102
- export async function endSession(userId: string, sessionId: string) {
103
- const client = await redis.getSessionClient()
104
- await client.delete(makeSessionID(userId, sessionId))
105
- }
106
-
107
- export async function getSession(
108
- userId: string,
109
- sessionId: string
110
- ): Promise<Session> {
111
- if (!userId || !sessionId) {
112
- throw new Error(`Invalid session details - ${userId} - ${sessionId}`)
113
- }
114
- const client = await redis.getSessionClient()
115
- const session = await client.get(makeSessionID(userId, sessionId))
116
- if (!session) {
117
- throw new Error(`Session not found - ${userId} - ${sessionId}`)
118
- }
119
- return session
120
- }
@@ -1,31 +0,0 @@
1
- import { encrypt, decrypt, SecretOption, getSecret } from "../encryption"
2
- import env from "../../environment"
3
-
4
- describe("encryption", () => {
5
- it("should throw an error if API encryption key is not set", () => {
6
- const jwt = getSecret(SecretOption.API)
7
- expect(jwt).toBe(env.JWT_SECRET)
8
- })
9
-
10
- it("should throw an error if encryption key is not set", () => {
11
- expect(() => getSecret(SecretOption.ENCRYPTION)).toThrow(
12
- 'Secret "ENCRYPTION_KEY" has not been set in environment.'
13
- )
14
- })
15
-
16
- it("should encrypt and decrypt a string using API encryption key", () => {
17
- env._set("API_ENCRYPTION_KEY", "api_secret")
18
- const plaintext = "budibase"
19
- const apiEncrypted = encrypt(plaintext, SecretOption.API)
20
- const decrypted = decrypt(apiEncrypted, SecretOption.API)
21
- expect(decrypted).toEqual(plaintext)
22
- })
23
-
24
- it("should encrypt and decrypt a string using encryption key", () => {
25
- env._set("ENCRYPTION_KEY", "normal_secret")
26
- const plaintext = "budibase"
27
- const encryptionEncrypted = encrypt(plaintext, SecretOption.ENCRYPTION)
28
- const decrypted = decrypt(encryptionEncrypted, SecretOption.ENCRYPTION)
29
- expect(decrypted).toEqual(plaintext)
30
- })
31
- })
@@ -1,145 +0,0 @@
1
- import cloneDeep from "lodash/cloneDeep"
2
- import * as permissions from "../permissions"
3
- import { BUILTIN_ROLE_IDS } from "../roles"
4
-
5
- describe("levelToNumber", () => {
6
- it("should return 0 for EXECUTE", () => {
7
- expect(permissions.levelToNumber(permissions.PermissionLevel.EXECUTE)).toBe(
8
- 0
9
- )
10
- })
11
-
12
- it("should return 1 for READ", () => {
13
- expect(permissions.levelToNumber(permissions.PermissionLevel.READ)).toBe(1)
14
- })
15
-
16
- it("should return 2 for WRITE", () => {
17
- expect(permissions.levelToNumber(permissions.PermissionLevel.WRITE)).toBe(2)
18
- })
19
-
20
- it("should return 3 for ADMIN", () => {
21
- expect(permissions.levelToNumber(permissions.PermissionLevel.ADMIN)).toBe(3)
22
- })
23
-
24
- it("should return -1 for an unknown permission level", () => {
25
- expect(
26
- permissions.levelToNumber("unknown" as permissions.PermissionLevel)
27
- ).toBe(-1)
28
- })
29
- })
30
- describe("getAllowedLevels", () => {
31
- it('should return ["execute"] for EXECUTE', () => {
32
- expect(
33
- permissions.getAllowedLevels(permissions.PermissionLevel.EXECUTE)
34
- ).toEqual([permissions.PermissionLevel.EXECUTE])
35
- })
36
-
37
- it('should return ["execute", "read"] for READ', () => {
38
- expect(
39
- permissions.getAllowedLevels(permissions.PermissionLevel.READ)
40
- ).toEqual([
41
- permissions.PermissionLevel.EXECUTE,
42
- permissions.PermissionLevel.READ,
43
- ])
44
- })
45
-
46
- it('should return ["execute", "read", "write"] for WRITE', () => {
47
- expect(
48
- permissions.getAllowedLevels(permissions.PermissionLevel.WRITE)
49
- ).toEqual([
50
- permissions.PermissionLevel.EXECUTE,
51
- permissions.PermissionLevel.READ,
52
- permissions.PermissionLevel.WRITE,
53
- ])
54
- })
55
-
56
- it('should return ["execute", "read", "write"] for ADMIN', () => {
57
- expect(
58
- permissions.getAllowedLevels(permissions.PermissionLevel.ADMIN)
59
- ).toEqual([
60
- permissions.PermissionLevel.EXECUTE,
61
- permissions.PermissionLevel.READ,
62
- permissions.PermissionLevel.WRITE,
63
- ])
64
- })
65
-
66
- it("should return [] for an unknown permission level", () => {
67
- expect(
68
- permissions.getAllowedLevels("unknown" as permissions.PermissionLevel)
69
- ).toEqual([])
70
- })
71
- })
72
-
73
- describe("doesHaveBasePermission", () => {
74
- it("should return true if base permission has the required level", () => {
75
- const permType = permissions.PermissionType.USER
76
- const permLevel = permissions.PermissionLevel.READ
77
- const rolesHierarchy = [
78
- {
79
- roleId: BUILTIN_ROLE_IDS.ADMIN,
80
- permissionId: permissions.BuiltinPermissionID.ADMIN,
81
- },
82
- ]
83
- expect(
84
- permissions.doesHaveBasePermission(permType, permLevel, rolesHierarchy)
85
- ).toBe(true)
86
- })
87
-
88
- it("should return false if base permission does not have the required level", () => {
89
- const permType = permissions.PermissionType.APP
90
- const permLevel = permissions.PermissionLevel.READ
91
- const rolesHierarchy = [
92
- {
93
- roleId: BUILTIN_ROLE_IDS.PUBLIC,
94
- permissionId: permissions.BuiltinPermissionID.PUBLIC,
95
- },
96
- ]
97
- expect(
98
- permissions.doesHaveBasePermission(permType, permLevel, rolesHierarchy)
99
- ).toBe(false)
100
- })
101
- })
102
-
103
- describe("isPermissionLevelHigherThanRead", () => {
104
- it("should return true if level is higher than read", () => {
105
- expect(
106
- permissions.isPermissionLevelHigherThanRead(
107
- permissions.PermissionLevel.WRITE
108
- )
109
- ).toBe(true)
110
- })
111
-
112
- it("should return false if level is read or lower", () => {
113
- expect(
114
- permissions.isPermissionLevelHigherThanRead(
115
- permissions.PermissionLevel.READ
116
- )
117
- ).toBe(false)
118
- })
119
- })
120
-
121
- describe("getBuiltinPermissions", () => {
122
- it("returns a clone of the builtin permissions", () => {
123
- const builtins = permissions.getBuiltinPermissions()
124
- expect(builtins).toEqual(cloneDeep(permissions.BUILTIN_PERMISSIONS))
125
- expect(builtins).not.toBe(permissions.BUILTIN_PERMISSIONS)
126
- })
127
- })
128
-
129
- describe("getBuiltinPermissionByID", () => {
130
- it("returns correct permission object for valid ID", () => {
131
- const expectedPermission = {
132
- _id: permissions.BuiltinPermissionID.PUBLIC,
133
- name: "Public",
134
- permissions: [
135
- new permissions.Permission(
136
- permissions.PermissionType.WEBHOOK,
137
- permissions.PermissionLevel.EXECUTE
138
- ),
139
- ],
140
- }
141
- expect(permissions.getBuiltinPermissionByID("public")).toEqual(
142
- expectedPermission
143
- )
144
- })
145
- })