@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
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
import { LockName, LockType, LockOptions } from "@budibase/types"
|
|
2
|
-
import { AUTO_EXTEND_POLLING_MS, doWithLock } from "../redlockImpl"
|
|
3
|
-
import { DBTestConfiguration, generator } from "../../../tests"
|
|
4
|
-
|
|
5
|
-
describe("redlockImpl", () => {
|
|
6
|
-
beforeEach(() => {
|
|
7
|
-
jest.useFakeTimers()
|
|
8
|
-
})
|
|
9
|
-
|
|
10
|
-
describe("doWithLock", () => {
|
|
11
|
-
const config = new DBTestConfiguration()
|
|
12
|
-
const lockTtl = AUTO_EXTEND_POLLING_MS
|
|
13
|
-
|
|
14
|
-
function runLockWithExecutionTime({
|
|
15
|
-
opts,
|
|
16
|
-
task,
|
|
17
|
-
executionTimeMs,
|
|
18
|
-
}: {
|
|
19
|
-
opts: LockOptions
|
|
20
|
-
task: () => Promise<string>
|
|
21
|
-
executionTimeMs: number
|
|
22
|
-
}) {
|
|
23
|
-
return config.doInTenant(() =>
|
|
24
|
-
doWithLock(opts, async () => {
|
|
25
|
-
// Run in multiple intervals until hitting the expected time
|
|
26
|
-
const interval = lockTtl / 10
|
|
27
|
-
for (let i = executionTimeMs; i > 0; i -= interval) {
|
|
28
|
-
await jest.advanceTimersByTimeAsync(interval)
|
|
29
|
-
}
|
|
30
|
-
return task()
|
|
31
|
-
})
|
|
32
|
-
)
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
it.each(Object.values(LockType))(
|
|
36
|
-
"should return the task value and release the lock",
|
|
37
|
-
async (lockType: LockType) => {
|
|
38
|
-
const expectedResult = generator.guid()
|
|
39
|
-
const mockTask = jest.fn().mockResolvedValue(expectedResult)
|
|
40
|
-
|
|
41
|
-
const opts: LockOptions = {
|
|
42
|
-
name: LockName.PERSIST_WRITETHROUGH,
|
|
43
|
-
type: lockType,
|
|
44
|
-
ttl: lockTtl,
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
const result = await runLockWithExecutionTime({
|
|
48
|
-
opts,
|
|
49
|
-
task: mockTask,
|
|
50
|
-
executionTimeMs: 0,
|
|
51
|
-
})
|
|
52
|
-
|
|
53
|
-
expect(result.executed).toBe(true)
|
|
54
|
-
expect(result.executed && result.result).toBe(expectedResult)
|
|
55
|
-
expect(mockTask).toHaveBeenCalledTimes(1)
|
|
56
|
-
}
|
|
57
|
-
)
|
|
58
|
-
|
|
59
|
-
it("should extend when type is autoextend", async () => {
|
|
60
|
-
const expectedResult = generator.guid()
|
|
61
|
-
const mockTask = jest.fn().mockResolvedValue(expectedResult)
|
|
62
|
-
const mockOnExtend = jest.fn()
|
|
63
|
-
|
|
64
|
-
const opts: LockOptions = {
|
|
65
|
-
name: LockName.PERSIST_WRITETHROUGH,
|
|
66
|
-
type: LockType.AUTO_EXTEND,
|
|
67
|
-
onExtend: mockOnExtend,
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
const result = await runLockWithExecutionTime({
|
|
71
|
-
opts,
|
|
72
|
-
task: mockTask,
|
|
73
|
-
executionTimeMs: lockTtl * 2.5,
|
|
74
|
-
})
|
|
75
|
-
|
|
76
|
-
expect(result.executed).toBe(true)
|
|
77
|
-
expect(result.executed && result.result).toBe(expectedResult)
|
|
78
|
-
expect(mockTask).toHaveBeenCalledTimes(1)
|
|
79
|
-
expect(mockOnExtend).toHaveBeenCalledTimes(5)
|
|
80
|
-
})
|
|
81
|
-
|
|
82
|
-
it.each(Object.values(LockType).filter(t => t !== LockType.AUTO_EXTEND))(
|
|
83
|
-
"should timeout when type is %s",
|
|
84
|
-
async (lockType: LockType) => {
|
|
85
|
-
const mockTask = jest.fn().mockResolvedValue("mockResult")
|
|
86
|
-
|
|
87
|
-
const opts: LockOptions = {
|
|
88
|
-
name: LockName.PERSIST_WRITETHROUGH,
|
|
89
|
-
type: lockType,
|
|
90
|
-
ttl: lockTtl,
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
await expect(
|
|
94
|
-
runLockWithExecutionTime({
|
|
95
|
-
opts,
|
|
96
|
-
task: mockTask,
|
|
97
|
-
executionTimeMs: lockTtl * 2,
|
|
98
|
-
})
|
|
99
|
-
).rejects.toThrow(
|
|
100
|
-
`Unable to fully release the lock on resource "lock:${config.tenantId}_persist_writethrough".`
|
|
101
|
-
)
|
|
102
|
-
}
|
|
103
|
-
)
|
|
104
|
-
})
|
|
105
|
-
})
|
package/src/redis/utils.ts
DELETED
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
import env from "../environment"
|
|
2
|
-
import * as Redis from "ioredis"
|
|
3
|
-
|
|
4
|
-
const SLOT_REFRESH_MS = 2000
|
|
5
|
-
const CONNECT_TIMEOUT_MS = 10000
|
|
6
|
-
export const SEPARATOR = "-"
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* These Redis databases help us to segment up a Redis keyspace by prepending the
|
|
10
|
-
* specified database name onto the cache key. This means that a single real Redis database
|
|
11
|
-
* can be split up a bit; allowing us to use scans on small databases to find some particular
|
|
12
|
-
* keys within.
|
|
13
|
-
* If writing a very large volume of keys is expected (say 10K+) then it is better to keep these out
|
|
14
|
-
* of the default keyspace and use a separate one - the SelectableDatabase can be used for this.
|
|
15
|
-
*/
|
|
16
|
-
export enum Databases {
|
|
17
|
-
PW_RESETS = "pwReset",
|
|
18
|
-
VERIFICATIONS = "verification",
|
|
19
|
-
INVITATIONS = "invitation",
|
|
20
|
-
DEV_LOCKS = "devLocks",
|
|
21
|
-
DEBOUNCE = "debounce",
|
|
22
|
-
SESSIONS = "session",
|
|
23
|
-
USER_CACHE = "users",
|
|
24
|
-
FLAGS = "flags",
|
|
25
|
-
APP_METADATA = "appMetadata",
|
|
26
|
-
QUERY_VARS = "queryVars",
|
|
27
|
-
LICENSES = "license",
|
|
28
|
-
GENERIC_CACHE = "data_cache",
|
|
29
|
-
WRITE_THROUGH = "writeThrough",
|
|
30
|
-
LOCKS = "locks",
|
|
31
|
-
SOCKET_IO = "socket_io",
|
|
32
|
-
BPM_EVENTS = "bpmEvents",
|
|
33
|
-
DOC_WRITE_THROUGH = "docWriteThrough",
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* These define the numeric Redis databases that can be access with the SELECT command -
|
|
38
|
-
* (https://redis.io/commands/select/). By default a Redis server/cluster will have 16 selectable
|
|
39
|
-
* databases, increasing this count increases the amount of CPU/memory required to run the server.
|
|
40
|
-
* Ideally new Redis keyspaces should be used sparingly, only when absolutely necessary for performance
|
|
41
|
-
* to be maintained. Generally a keyspace can grow to be very large is scans are not needed or desired,
|
|
42
|
-
* but if you need to walk through all values in a database periodically then a separate selectable
|
|
43
|
-
* keyspace should be used.
|
|
44
|
-
*/
|
|
45
|
-
export enum SelectableDatabase {
|
|
46
|
-
DEFAULT = 0,
|
|
47
|
-
SOCKET_IO = 1,
|
|
48
|
-
RATE_LIMITING = 2,
|
|
49
|
-
UNUSED_2 = 3,
|
|
50
|
-
UNUSED_3 = 4,
|
|
51
|
-
UNUSED_4 = 5,
|
|
52
|
-
UNUSED_5 = 6,
|
|
53
|
-
UNUSED_6 = 7,
|
|
54
|
-
UNUSED_7 = 8,
|
|
55
|
-
UNUSED_8 = 9,
|
|
56
|
-
UNUSED_9 = 10,
|
|
57
|
-
UNUSED_10 = 11,
|
|
58
|
-
UNUSED_11 = 12,
|
|
59
|
-
UNUSED_12 = 13,
|
|
60
|
-
UNUSED_13 = 14,
|
|
61
|
-
UNUSED_14 = 15,
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
export function getRedisConnectionDetails() {
|
|
65
|
-
let password = env.REDIS_PASSWORD
|
|
66
|
-
let url: string[] | string = env.REDIS_URL.split("//")
|
|
67
|
-
// get rid of the protocol
|
|
68
|
-
url = url.length > 1 ? url[1] : url[0]
|
|
69
|
-
// check for a password etc
|
|
70
|
-
url = url.split("@")
|
|
71
|
-
if (url.length > 1) {
|
|
72
|
-
// get the password
|
|
73
|
-
password = url[0].split(":")[1]
|
|
74
|
-
url = url[1]
|
|
75
|
-
} else {
|
|
76
|
-
url = url[0]
|
|
77
|
-
}
|
|
78
|
-
const [host, port] = url.split(":")
|
|
79
|
-
|
|
80
|
-
const portNumber = parseInt(port)
|
|
81
|
-
return {
|
|
82
|
-
host,
|
|
83
|
-
password,
|
|
84
|
-
// assume default port for redis if invalid found
|
|
85
|
-
port: isNaN(portNumber) ? 6379 : portNumber,
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
export function getRedisOptions() {
|
|
90
|
-
const { host, password, port } = getRedisConnectionDetails()
|
|
91
|
-
let redisOpts: Redis.RedisOptions = {
|
|
92
|
-
connectTimeout: CONNECT_TIMEOUT_MS,
|
|
93
|
-
port: port,
|
|
94
|
-
host,
|
|
95
|
-
password,
|
|
96
|
-
}
|
|
97
|
-
let opts: Redis.ClusterOptions | Redis.RedisOptions = redisOpts
|
|
98
|
-
if (env.REDIS_CLUSTERED) {
|
|
99
|
-
opts = {
|
|
100
|
-
connectTimeout: CONNECT_TIMEOUT_MS,
|
|
101
|
-
redisOptions: {
|
|
102
|
-
...redisOpts,
|
|
103
|
-
tls: {},
|
|
104
|
-
},
|
|
105
|
-
slotsRefreshTimeout: SLOT_REFRESH_MS,
|
|
106
|
-
dnsLookup: (address: string, callback: any) => callback(null, address),
|
|
107
|
-
} as Redis.ClusterOptions
|
|
108
|
-
}
|
|
109
|
-
return opts
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
export function addDbPrefix(db: string, key: string) {
|
|
113
|
-
if (key.includes(db)) {
|
|
114
|
-
return key
|
|
115
|
-
}
|
|
116
|
-
return `${db}${SEPARATOR}${key}`
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
export function removeDbPrefix(key: string) {
|
|
120
|
-
let parts = key.split(SEPARATOR)
|
|
121
|
-
if (parts.length >= 2) {
|
|
122
|
-
parts.shift()
|
|
123
|
-
return parts.join(SEPARATOR)
|
|
124
|
-
} else {
|
|
125
|
-
// return the only part
|
|
126
|
-
return parts[0]
|
|
127
|
-
}
|
|
128
|
-
}
|
package/src/security/auth.ts
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import env from "../environment"
|
|
2
|
-
|
|
3
|
-
export const PASSWORD_MIN_LENGTH = +(env.PASSWORD_MIN_LENGTH || 12)
|
|
4
|
-
export const PASSWORD_MAX_LENGTH = +(env.PASSWORD_MAX_LENGTH || 512)
|
|
5
|
-
|
|
6
|
-
export function validatePassword(
|
|
7
|
-
password: string
|
|
8
|
-
): { valid: true } | { valid: false; error: string } {
|
|
9
|
-
if (!password || password.length < PASSWORD_MIN_LENGTH) {
|
|
10
|
-
return {
|
|
11
|
-
valid: false,
|
|
12
|
-
error: `Password invalid. Minimum ${PASSWORD_MIN_LENGTH} characters.`,
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
if (password.length > PASSWORD_MAX_LENGTH) {
|
|
17
|
-
return {
|
|
18
|
-
valid: false,
|
|
19
|
-
error: `Password invalid. Maximum ${PASSWORD_MAX_LENGTH} characters.`,
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
return { valid: true }
|
|
24
|
-
}
|
|
@@ -1,185 +0,0 @@
|
|
|
1
|
-
import crypto from "crypto"
|
|
2
|
-
import fs from "fs"
|
|
3
|
-
import zlib from "zlib"
|
|
4
|
-
import env from "../environment"
|
|
5
|
-
import { join } from "path"
|
|
6
|
-
|
|
7
|
-
const ALGO = "aes-256-ctr"
|
|
8
|
-
const SEPARATOR = "-"
|
|
9
|
-
const ITERATIONS = 10000
|
|
10
|
-
const STRETCH_LENGTH = 32
|
|
11
|
-
|
|
12
|
-
const SALT_LENGTH = 16
|
|
13
|
-
const IV_LENGTH = 16
|
|
14
|
-
|
|
15
|
-
export enum SecretOption {
|
|
16
|
-
API = "api",
|
|
17
|
-
ENCRYPTION = "encryption",
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export function getSecret(secretOption: SecretOption): string {
|
|
21
|
-
let secret, secretName
|
|
22
|
-
switch (secretOption) {
|
|
23
|
-
case SecretOption.ENCRYPTION:
|
|
24
|
-
secret = env.ENCRYPTION_KEY
|
|
25
|
-
secretName = "ENCRYPTION_KEY"
|
|
26
|
-
break
|
|
27
|
-
case SecretOption.API:
|
|
28
|
-
default:
|
|
29
|
-
secret = env.API_ENCRYPTION_KEY
|
|
30
|
-
secretName = "API_ENCRYPTION_KEY"
|
|
31
|
-
break
|
|
32
|
-
}
|
|
33
|
-
if (!secret) {
|
|
34
|
-
throw new Error(`Secret "${secretName}" has not been set in environment.`)
|
|
35
|
-
}
|
|
36
|
-
return secret
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
function stretchString(secret: string, salt: Buffer) {
|
|
40
|
-
return crypto.pbkdf2Sync(secret, salt, ITERATIONS, STRETCH_LENGTH, "sha512")
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export function encrypt(
|
|
44
|
-
input: string,
|
|
45
|
-
secretOption: SecretOption = SecretOption.API
|
|
46
|
-
) {
|
|
47
|
-
const salt = crypto.randomBytes(SALT_LENGTH)
|
|
48
|
-
const stretched = stretchString(getSecret(secretOption), salt)
|
|
49
|
-
const cipher = crypto.createCipheriv(ALGO, stretched, salt)
|
|
50
|
-
const base = cipher.update(input)
|
|
51
|
-
const final = cipher.final()
|
|
52
|
-
const encrypted = Buffer.concat([base, final]).toString("hex")
|
|
53
|
-
return `${salt.toString("hex")}${SEPARATOR}${encrypted}`
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
export function decrypt(
|
|
57
|
-
input: string,
|
|
58
|
-
secretOption: SecretOption = SecretOption.API
|
|
59
|
-
) {
|
|
60
|
-
const [salt, encrypted] = input.split(SEPARATOR)
|
|
61
|
-
const saltBuffer = Buffer.from(salt, "hex")
|
|
62
|
-
const stretched = stretchString(getSecret(secretOption), saltBuffer)
|
|
63
|
-
const decipher = crypto.createDecipheriv(ALGO, stretched, saltBuffer)
|
|
64
|
-
const base = decipher.update(Buffer.from(encrypted, "hex"))
|
|
65
|
-
const final = decipher.final()
|
|
66
|
-
return Buffer.concat([base, final]).toString()
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
export async function encryptFile(
|
|
70
|
-
{ dir, filename }: { dir: string; filename: string },
|
|
71
|
-
secret: string
|
|
72
|
-
) {
|
|
73
|
-
const outputFileName = `${filename}.enc`
|
|
74
|
-
|
|
75
|
-
const filePath = join(dir, filename)
|
|
76
|
-
if (fs.lstatSync(filePath).isDirectory()) {
|
|
77
|
-
throw new Error("Unable to encrypt directory")
|
|
78
|
-
}
|
|
79
|
-
const inputFile = fs.createReadStream(filePath)
|
|
80
|
-
const outputFile = fs.createWriteStream(join(dir, outputFileName))
|
|
81
|
-
|
|
82
|
-
const salt = crypto.randomBytes(SALT_LENGTH)
|
|
83
|
-
const iv = crypto.randomBytes(IV_LENGTH)
|
|
84
|
-
const stretched = stretchString(secret, salt)
|
|
85
|
-
const cipher = crypto.createCipheriv(ALGO, stretched, iv)
|
|
86
|
-
|
|
87
|
-
outputFile.write(salt)
|
|
88
|
-
outputFile.write(iv)
|
|
89
|
-
|
|
90
|
-
inputFile.pipe(zlib.createGzip()).pipe(cipher).pipe(outputFile)
|
|
91
|
-
|
|
92
|
-
return new Promise<{ filename: string; dir: string }>(r => {
|
|
93
|
-
outputFile.on("finish", () => {
|
|
94
|
-
r({
|
|
95
|
-
filename: outputFileName,
|
|
96
|
-
dir,
|
|
97
|
-
})
|
|
98
|
-
})
|
|
99
|
-
})
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
async function getSaltAndIV(path: string) {
|
|
103
|
-
const fileStream = fs.createReadStream(path)
|
|
104
|
-
|
|
105
|
-
const salt = await readBytes(fileStream, SALT_LENGTH)
|
|
106
|
-
const iv = await readBytes(fileStream, IV_LENGTH)
|
|
107
|
-
fileStream.close()
|
|
108
|
-
return { salt, iv }
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
export async function decryptFile(
|
|
112
|
-
inputPath: string,
|
|
113
|
-
outputPath: string,
|
|
114
|
-
secret: string
|
|
115
|
-
) {
|
|
116
|
-
if (fs.lstatSync(inputPath).isDirectory()) {
|
|
117
|
-
throw new Error("Unable to encrypt directory")
|
|
118
|
-
}
|
|
119
|
-
const { salt, iv } = await getSaltAndIV(inputPath)
|
|
120
|
-
const inputFile = fs.createReadStream(inputPath, {
|
|
121
|
-
start: SALT_LENGTH + IV_LENGTH,
|
|
122
|
-
})
|
|
123
|
-
|
|
124
|
-
const outputFile = fs.createWriteStream(outputPath)
|
|
125
|
-
|
|
126
|
-
const stretched = stretchString(secret, salt)
|
|
127
|
-
const decipher = crypto.createDecipheriv(ALGO, stretched, iv)
|
|
128
|
-
|
|
129
|
-
const unzip = zlib.createGunzip()
|
|
130
|
-
|
|
131
|
-
inputFile.pipe(decipher).pipe(unzip).pipe(outputFile)
|
|
132
|
-
|
|
133
|
-
return new Promise<void>((res, rej) => {
|
|
134
|
-
outputFile.on("finish", () => {
|
|
135
|
-
outputFile.close()
|
|
136
|
-
res()
|
|
137
|
-
})
|
|
138
|
-
|
|
139
|
-
inputFile.on("error", e => {
|
|
140
|
-
outputFile.close()
|
|
141
|
-
rej(e)
|
|
142
|
-
})
|
|
143
|
-
|
|
144
|
-
decipher.on("error", e => {
|
|
145
|
-
outputFile.close()
|
|
146
|
-
rej(e)
|
|
147
|
-
})
|
|
148
|
-
|
|
149
|
-
unzip.on("error", e => {
|
|
150
|
-
outputFile.close()
|
|
151
|
-
rej(e)
|
|
152
|
-
})
|
|
153
|
-
|
|
154
|
-
outputFile.on("error", e => {
|
|
155
|
-
outputFile.close()
|
|
156
|
-
rej(e)
|
|
157
|
-
})
|
|
158
|
-
})
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
function readBytes(stream: fs.ReadStream, length: number) {
|
|
162
|
-
return new Promise<Buffer>((resolve, reject) => {
|
|
163
|
-
let bytesRead = 0
|
|
164
|
-
const data: Buffer[] = []
|
|
165
|
-
|
|
166
|
-
stream.on("readable", () => {
|
|
167
|
-
let chunk
|
|
168
|
-
|
|
169
|
-
while ((chunk = stream.read(length - bytesRead)) !== null) {
|
|
170
|
-
data.push(chunk)
|
|
171
|
-
bytesRead += chunk.length
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
resolve(Buffer.concat(data))
|
|
175
|
-
})
|
|
176
|
-
|
|
177
|
-
stream.on("end", () => {
|
|
178
|
-
reject(new Error("Insufficient data in the stream."))
|
|
179
|
-
})
|
|
180
|
-
|
|
181
|
-
stream.on("error", error => {
|
|
182
|
-
reject(error)
|
|
183
|
-
})
|
|
184
|
-
})
|
|
185
|
-
}
|
package/src/security/index.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from "./auth"
|
|
@@ -1,166 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
PermissionLevel,
|
|
3
|
-
PermissionType,
|
|
4
|
-
BuiltinPermissionID,
|
|
5
|
-
} from "@budibase/types"
|
|
6
|
-
import flatten from "lodash/flatten"
|
|
7
|
-
import cloneDeep from "lodash/fp/cloneDeep"
|
|
8
|
-
|
|
9
|
-
export { PermissionType, PermissionLevel } from "@budibase/types"
|
|
10
|
-
|
|
11
|
-
export type RoleHierarchy = {
|
|
12
|
-
permissionId: string
|
|
13
|
-
}[]
|
|
14
|
-
|
|
15
|
-
export class Permission {
|
|
16
|
-
type: PermissionType
|
|
17
|
-
level: PermissionLevel
|
|
18
|
-
|
|
19
|
-
constructor(type: PermissionType, level: PermissionLevel) {
|
|
20
|
-
this.type = type
|
|
21
|
-
this.level = level
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export function levelToNumber(perm: PermissionLevel) {
|
|
26
|
-
switch (perm) {
|
|
27
|
-
// not everything has execute privileges
|
|
28
|
-
case PermissionLevel.EXECUTE:
|
|
29
|
-
return 0
|
|
30
|
-
case PermissionLevel.READ:
|
|
31
|
-
return 1
|
|
32
|
-
case PermissionLevel.WRITE:
|
|
33
|
-
return 2
|
|
34
|
-
case PermissionLevel.ADMIN:
|
|
35
|
-
return 3
|
|
36
|
-
default:
|
|
37
|
-
return -1
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Given the specified permission level for the user return the levels they are allowed to carry out.
|
|
43
|
-
* @param userPermLevel The permission level of the user.
|
|
44
|
-
* @return All the permission levels this user is allowed to carry out.
|
|
45
|
-
*/
|
|
46
|
-
export function getAllowedLevels(userPermLevel: PermissionLevel): string[] {
|
|
47
|
-
switch (userPermLevel) {
|
|
48
|
-
case PermissionLevel.EXECUTE:
|
|
49
|
-
return [PermissionLevel.EXECUTE]
|
|
50
|
-
case PermissionLevel.READ:
|
|
51
|
-
return [PermissionLevel.EXECUTE, PermissionLevel.READ]
|
|
52
|
-
case PermissionLevel.WRITE:
|
|
53
|
-
case PermissionLevel.ADMIN:
|
|
54
|
-
return [
|
|
55
|
-
PermissionLevel.EXECUTE,
|
|
56
|
-
PermissionLevel.READ,
|
|
57
|
-
PermissionLevel.WRITE,
|
|
58
|
-
]
|
|
59
|
-
default:
|
|
60
|
-
return []
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
export const BUILTIN_PERMISSIONS: {
|
|
65
|
-
[key in keyof typeof BuiltinPermissionID]: {
|
|
66
|
-
_id: (typeof BuiltinPermissionID)[key]
|
|
67
|
-
name: string
|
|
68
|
-
permissions: Permission[]
|
|
69
|
-
}
|
|
70
|
-
} = {
|
|
71
|
-
PUBLIC: {
|
|
72
|
-
_id: BuiltinPermissionID.PUBLIC,
|
|
73
|
-
name: "Public",
|
|
74
|
-
permissions: [
|
|
75
|
-
new Permission(PermissionType.WEBHOOK, PermissionLevel.EXECUTE),
|
|
76
|
-
],
|
|
77
|
-
},
|
|
78
|
-
READ_ONLY: {
|
|
79
|
-
_id: BuiltinPermissionID.READ_ONLY,
|
|
80
|
-
name: "Read only",
|
|
81
|
-
permissions: [
|
|
82
|
-
new Permission(PermissionType.QUERY, PermissionLevel.READ),
|
|
83
|
-
new Permission(PermissionType.TABLE, PermissionLevel.READ),
|
|
84
|
-
new Permission(PermissionType.APP, PermissionLevel.READ),
|
|
85
|
-
],
|
|
86
|
-
},
|
|
87
|
-
WRITE: {
|
|
88
|
-
_id: BuiltinPermissionID.WRITE,
|
|
89
|
-
name: "Read/Write",
|
|
90
|
-
permissions: [
|
|
91
|
-
new Permission(PermissionType.QUERY, PermissionLevel.WRITE),
|
|
92
|
-
new Permission(PermissionType.TABLE, PermissionLevel.WRITE),
|
|
93
|
-
new Permission(PermissionType.AUTOMATION, PermissionLevel.EXECUTE),
|
|
94
|
-
new Permission(PermissionType.LEGACY_VIEW, PermissionLevel.READ),
|
|
95
|
-
new Permission(PermissionType.APP, PermissionLevel.READ),
|
|
96
|
-
],
|
|
97
|
-
},
|
|
98
|
-
POWER: {
|
|
99
|
-
_id: BuiltinPermissionID.POWER,
|
|
100
|
-
name: "Power",
|
|
101
|
-
permissions: [
|
|
102
|
-
new Permission(PermissionType.TABLE, PermissionLevel.WRITE),
|
|
103
|
-
new Permission(PermissionType.USER, PermissionLevel.READ),
|
|
104
|
-
new Permission(PermissionType.AUTOMATION, PermissionLevel.EXECUTE),
|
|
105
|
-
new Permission(PermissionType.WEBHOOK, PermissionLevel.READ),
|
|
106
|
-
new Permission(PermissionType.LEGACY_VIEW, PermissionLevel.READ),
|
|
107
|
-
new Permission(PermissionType.APP, PermissionLevel.READ),
|
|
108
|
-
],
|
|
109
|
-
},
|
|
110
|
-
ADMIN: {
|
|
111
|
-
_id: BuiltinPermissionID.ADMIN,
|
|
112
|
-
name: "Admin",
|
|
113
|
-
permissions: [
|
|
114
|
-
new Permission(PermissionType.TABLE, PermissionLevel.ADMIN),
|
|
115
|
-
new Permission(PermissionType.USER, PermissionLevel.ADMIN),
|
|
116
|
-
new Permission(PermissionType.AUTOMATION, PermissionLevel.ADMIN),
|
|
117
|
-
new Permission(PermissionType.WEBHOOK, PermissionLevel.READ),
|
|
118
|
-
new Permission(PermissionType.QUERY, PermissionLevel.ADMIN),
|
|
119
|
-
new Permission(PermissionType.LEGACY_VIEW, PermissionLevel.READ),
|
|
120
|
-
new Permission(PermissionType.APP, PermissionLevel.READ),
|
|
121
|
-
],
|
|
122
|
-
},
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
export function getBuiltinPermissions() {
|
|
126
|
-
return cloneDeep(BUILTIN_PERMISSIONS)
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
export function getBuiltinPermissionByID(id: string) {
|
|
130
|
-
const perms = Object.values(BUILTIN_PERMISSIONS)
|
|
131
|
-
return perms.find(perm => perm._id === id)
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
export function doesHaveBasePermission(
|
|
135
|
-
permType: PermissionType,
|
|
136
|
-
permLevel: PermissionLevel,
|
|
137
|
-
rolesHierarchy: RoleHierarchy
|
|
138
|
-
) {
|
|
139
|
-
const basePermissions = [
|
|
140
|
-
...new Set(rolesHierarchy.map(role => role.permissionId)),
|
|
141
|
-
]
|
|
142
|
-
const builtins = Object.values(BUILTIN_PERMISSIONS)
|
|
143
|
-
let permissions = flatten(
|
|
144
|
-
builtins
|
|
145
|
-
.filter(builtin => basePermissions.indexOf(builtin._id) !== -1)
|
|
146
|
-
.map(builtin => builtin.permissions)
|
|
147
|
-
)
|
|
148
|
-
for (let permission of permissions) {
|
|
149
|
-
if (
|
|
150
|
-
permission.type === permType &&
|
|
151
|
-
getAllowedLevels(permission.level).indexOf(permLevel) !== -1
|
|
152
|
-
) {
|
|
153
|
-
return true
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
return false
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
export function isPermissionLevelHigherThanRead(level: PermissionLevel) {
|
|
160
|
-
return levelToNumber(level) > 1
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
// utility as a lot of things need simply the builder permission
|
|
164
|
-
export const BUILDER = PermissionType.BUILDER
|
|
165
|
-
export const CREATOR = PermissionType.CREATOR
|
|
166
|
-
export const GLOBAL_BUILDER = PermissionType.GLOBAL_BUILDER
|