@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.
- package/dist/index.js +266 -324
- package/dist/index.js.map +4 -4
- package/dist/index.js.meta.json +1 -1
- package/dist/package.json +19 -4
- package/dist/plugins.js +1 -1
- package/dist/plugins.js.map +1 -1
- package/dist/plugins.js.meta.json +1 -1
- package/dist/src/security/permissions.d.ts +1 -1
- package/dist/tests.js +222 -260
- package/dist/tests.js.map +4 -4
- package/dist/tests.js.meta.json +1 -1
- package/package.json +19 -4
- package/dist/tsconfig.build.tsbuildinfo +0 -1
- 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 -208
- 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 -92
- package/src/cache/generic.ts +0 -30
- package/src/cache/index.ts +0 -5
- package/src/cache/tests/writethrough.spec.ts +0 -138
- package/src/cache/user.ts +0 -69
- package/src/cache/writethrough.ts +0 -133
- package/src/configs/configs.ts +0 -257
- package/src/configs/index.ts +0 -1
- package/src/configs/tests/configs.spec.ts +0 -184
- package/src/constants/db.ts +0 -63
- package/src/constants/index.ts +0 -2
- package/src/constants/misc.ts +0 -50
- 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 -310
- package/src/context/tests/index.spec.ts +0 -147
- package/src/context/types.ts +0 -11
- package/src/db/Replication.ts +0 -84
- package/src/db/constants.ts +0 -10
- package/src/db/couch/DatabaseImpl.ts +0 -238
- package/src/db/couch/connections.ts +0 -77
- package/src/db/couch/index.ts +0 -5
- package/src/db/couch/pouchDB.ts +0 -97
- package/src/db/couch/pouchDump.ts +0 -0
- package/src/db/couch/utils.ts +0 -50
- package/src/db/db.ts +0 -39
- package/src/db/errors.ts +0 -14
- package/src/db/index.ts +0 -12
- package/src/db/lucene.ts +0 -732
- package/src/db/searchIndexes/index.ts +0 -1
- package/src/db/searchIndexes/searchIndexes.ts +0 -62
- package/src/db/tests/index.spec.js +0 -25
- package/src/db/tests/lucene.spec.ts +0 -298
- package/src/db/tests/pouch.spec.js +0 -62
- package/src/db/tests/utils.spec.ts +0 -63
- package/src/db/utils.ts +0 -207
- package/src/db/views.ts +0 -241
- package/src/docIds/conversions.ts +0 -59
- package/src/docIds/ids.ts +0 -113
- package/src/docIds/index.ts +0 -2
- package/src/docIds/newid.ts +0 -5
- package/src/docIds/params.ts +0 -174
- package/src/docUpdates/index.ts +0 -29
- package/src/environment.ts +0 -201
- 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 -40
- package/src/events/identification.ts +0 -310
- package/src/events/index.ts +0 -14
- package/src/events/processors/AnalyticsProcessor.ts +0 -64
- package/src/events/processors/AuditLogsProcessor.ts +0 -93
- package/src/events/processors/LoggingProcessor.ts +0 -37
- package/src/events/processors/Processors.ts +0 -52
- package/src/events/processors/async/DocumentUpdateProcessor.ts +0 -43
- 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 -2
- package/src/events/processors/posthog/rateLimiting.ts +0 -106
- package/src/events/processors/posthog/tests/PosthogProcessor.spec.ts +0 -168
- package/src/events/processors/types.ts +0 -1
- package/src/events/publishers/account.ts +0 -35
- package/src/events/publishers/app.ts +0 -155
- 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 -24
- 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 -88
- 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/featureFlags/index.ts +0 -77
- package/src/featureFlags/tests/featureFlags.spec.ts +0 -85
- package/src/helpers.ts +0 -9
- package/src/index.ts +0 -53
- package/src/installation.ts +0 -107
- package/src/logging/alerts.ts +0 -26
- package/src/logging/correlation/correlation.ts +0 -13
- package/src/logging/correlation/index.ts +0 -1
- package/src/logging/correlation/middleware.ts +0 -17
- package/src/logging/index.ts +0 -4
- package/src/logging/pino/logger.ts +0 -232
- package/src/logging/pino/middleware.ts +0 -45
- 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 -193
- package/src/middleware/builderOnly.ts +0 -20
- package/src/middleware/builderOrAdmin.ts +0 -20
- package/src/middleware/csrf.ts +0 -81
- package/src/middleware/errorHandling.ts +0 -29
- package/src/middleware/index.ts +0 -21
- package/src/middleware/internalApi.ts +0 -23
- package/src/middleware/joi-validator.ts +0 -45
- package/src/middleware/matchers.ts +0 -47
- package/src/middleware/passport/datasource/google.ts +0 -95
- 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 -154
- package/src/middleware/passport/sso/sso.ts +0 -165
- package/src/middleware/passport/sso/tests/google.spec.ts +0 -67
- package/src/middleware/passport/sso/tests/oidc.spec.ts +0 -152
- 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 -180
- package/src/middleware/tests/matchers.spec.ts +0 -134
- package/src/migrations/definitions.ts +0 -40
- package/src/migrations/index.ts +0 -2
- package/src/migrations/migrations.ts +0 -191
- 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 -40
- 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 -171
- 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 -440
- package/src/objectStore/utils.ts +0 -27
- 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 -90
- package/src/plugin/index.ts +0 -1
- package/src/plugin/tests/validation.spec.ts +0 -83
- package/src/plugin/utils.ts +0 -156
- package/src/queue/constants.ts +0 -6
- package/src/queue/inMemoryQueue.ts +0 -141
- package/src/queue/index.ts +0 -2
- package/src/queue/listeners.ts +0 -195
- package/src/queue/queue.ts +0 -54
- package/src/redis/index.ts +0 -6
- package/src/redis/init.ts +0 -86
- package/src/redis/redis.ts +0 -308
- package/src/redis/redlockImpl.ts +0 -139
- package/src/redis/utils.ts +0 -117
- package/src/security/encryption.ts +0 -179
- package/src/security/permissions.ts +0 -159
- package/src/security/roles.ts +0 -420
- package/src/security/sessions.ts +0 -120
- package/src/security/tests/encryption.spec.ts +0 -31
- package/src/security/tests/permissions.spec.ts +0 -145
- package/src/security/tests/sessions.spec.ts +0 -12
- package/src/tenancy/db.ts +0 -6
- package/src/tenancy/index.ts +0 -2
- package/src/tenancy/tenancy.ts +0 -140
- 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 -460
- package/src/users/events.ts +0 -176
- package/src/users/index.ts +0 -4
- package/src/users/lookup.ts +0 -102
- package/src/users/users.ts +0 -276
- package/src/users/utils.ts +0 -55
- package/src/utils/hashing.ts +0 -14
- package/src/utils/index.ts +0 -3
- package/src/utils/stringUtils.ts +0 -8
- package/src/utils/tests/utils.spec.ts +0 -191
- package/src/utils/utils.ts +0 -239
- package/tests/core/logging.ts +0 -34
- package/tests/core/utilities/index.ts +0 -6
- package/tests/core/utilities/jestUtils.ts +0 -30
- package/tests/core/utilities/mocks/alerts.ts +0 -3
- package/tests/core/utilities/mocks/date.ts +0 -2
- package/tests/core/utilities/mocks/events.ts +0 -131
- package/tests/core/utilities/mocks/fetch.ts +0 -17
- package/tests/core/utilities/mocks/index.ts +0 -10
- package/tests/core/utilities/mocks/licenses.ts +0 -107
- package/tests/core/utilities/mocks/posthog.ts +0 -7
- package/tests/core/utilities/structures/Chance.ts +0 -20
- package/tests/core/utilities/structures/accounts.ts +0 -115
- 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 -2
- 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 -167
- package/tests/core/utilities/structures/plugins.ts +0 -19
- package/tests/core/utilities/structures/quotas.ts +0 -67
- package/tests/core/utilities/structures/scim.ts +0 -80
- package/tests/core/utilities/structures/shared.ts +0 -19
- package/tests/core/utilities/structures/sso.ts +0 -119
- 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 -73
- package/tests/core/utilities/testContainerUtils.ts +0 -98
- package/tests/core/utilities/utils/index.ts +0 -1
- 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 -1
- package/tests/jestEnv.ts +0 -6
- package/tests/jestSetup.ts +0 -28
|
@@ -1,440 +0,0 @@
|
|
|
1
|
-
const sanitize = require("sanitize-s3-objectkey")
|
|
2
|
-
import AWS from "aws-sdk"
|
|
3
|
-
import stream from "stream"
|
|
4
|
-
import fetch from "node-fetch"
|
|
5
|
-
import tar from "tar-fs"
|
|
6
|
-
import zlib from "zlib"
|
|
7
|
-
import { promisify } from "util"
|
|
8
|
-
import { join } from "path"
|
|
9
|
-
import fs from "fs"
|
|
10
|
-
import env from "../environment"
|
|
11
|
-
import { budibaseTempDir } from "./utils"
|
|
12
|
-
import { v4 } from "uuid"
|
|
13
|
-
import { APP_PREFIX, APP_DEV_PREFIX } from "../db"
|
|
14
|
-
|
|
15
|
-
const streamPipeline = promisify(stream.pipeline)
|
|
16
|
-
// use this as a temporary store of buckets that are being created
|
|
17
|
-
const STATE = {
|
|
18
|
-
bucketCreationPromises: {},
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
type ListParams = {
|
|
22
|
-
ContinuationToken?: string
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
type UploadParams = {
|
|
26
|
-
bucket: string
|
|
27
|
-
filename: string
|
|
28
|
-
path: string
|
|
29
|
-
type?: string | null
|
|
30
|
-
// can be undefined, we will remove it
|
|
31
|
-
metadata?: {
|
|
32
|
-
[key: string]: string | undefined
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
const CONTENT_TYPE_MAP: any = {
|
|
37
|
-
txt: "text/plain",
|
|
38
|
-
html: "text/html",
|
|
39
|
-
css: "text/css",
|
|
40
|
-
js: "application/javascript",
|
|
41
|
-
json: "application/json",
|
|
42
|
-
gz: "application/gzip",
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
const STRING_CONTENT_TYPES = [
|
|
46
|
-
CONTENT_TYPE_MAP.html,
|
|
47
|
-
CONTENT_TYPE_MAP.css,
|
|
48
|
-
CONTENT_TYPE_MAP.js,
|
|
49
|
-
CONTENT_TYPE_MAP.json,
|
|
50
|
-
]
|
|
51
|
-
|
|
52
|
-
// does normal sanitization and then swaps dev apps to apps
|
|
53
|
-
export function sanitizeKey(input: string) {
|
|
54
|
-
return sanitize(sanitizeBucket(input)).replace(/\\/g, "/")
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// simply handles the dev app to app conversion
|
|
58
|
-
export function sanitizeBucket(input: string) {
|
|
59
|
-
return input.replace(new RegExp(APP_DEV_PREFIX, "g"), APP_PREFIX)
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Gets a connection to the object store using the S3 SDK.
|
|
64
|
-
* @param {string} bucket the name of the bucket which blobs will be uploaded/retrieved from.
|
|
65
|
-
* @param {object} opts configuration for the object store.
|
|
66
|
-
* @return {Object} an S3 object store object, check S3 Nodejs SDK for usage.
|
|
67
|
-
* @constructor
|
|
68
|
-
*/
|
|
69
|
-
export const ObjectStore = (
|
|
70
|
-
bucket: string,
|
|
71
|
-
opts: { presigning: boolean } = { presigning: false }
|
|
72
|
-
) => {
|
|
73
|
-
const config: any = {
|
|
74
|
-
s3ForcePathStyle: true,
|
|
75
|
-
signatureVersion: "v4",
|
|
76
|
-
apiVersion: "2006-03-01",
|
|
77
|
-
accessKeyId: env.MINIO_ACCESS_KEY,
|
|
78
|
-
secretAccessKey: env.MINIO_SECRET_KEY,
|
|
79
|
-
region: env.AWS_REGION,
|
|
80
|
-
}
|
|
81
|
-
if (bucket) {
|
|
82
|
-
config.params = {
|
|
83
|
-
Bucket: sanitizeBucket(bucket),
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// custom S3 is in use i.e. minio
|
|
88
|
-
if (env.MINIO_URL) {
|
|
89
|
-
if (opts.presigning && env.MINIO_ENABLED) {
|
|
90
|
-
// IMPORTANT: Signed urls will inspect the host header of the request.
|
|
91
|
-
// Normally a signed url will need to be generated with a specified host in mind.
|
|
92
|
-
// To support dynamic hosts, e.g. some unknown self-hosted installation url,
|
|
93
|
-
// use a predefined host. The host 'minio-service' is also forwarded to minio requests via nginx
|
|
94
|
-
config.endpoint = "minio-service"
|
|
95
|
-
} else {
|
|
96
|
-
config.endpoint = env.MINIO_URL
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
return new AWS.S3(config)
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* Given an object store and a bucket name this will make sure the bucket exists,
|
|
105
|
-
* if it does not exist then it will create it.
|
|
106
|
-
*/
|
|
107
|
-
export const makeSureBucketExists = async (client: any, bucketName: string) => {
|
|
108
|
-
bucketName = sanitizeBucket(bucketName)
|
|
109
|
-
try {
|
|
110
|
-
await client
|
|
111
|
-
.headBucket({
|
|
112
|
-
Bucket: bucketName,
|
|
113
|
-
})
|
|
114
|
-
.promise()
|
|
115
|
-
} catch (err: any) {
|
|
116
|
-
const promises: any = STATE.bucketCreationPromises
|
|
117
|
-
const doesntExist = err.statusCode === 404,
|
|
118
|
-
noAccess = err.statusCode === 403
|
|
119
|
-
if (promises[bucketName]) {
|
|
120
|
-
await promises[bucketName]
|
|
121
|
-
} else if (doesntExist || noAccess) {
|
|
122
|
-
if (doesntExist) {
|
|
123
|
-
// bucket doesn't exist create it
|
|
124
|
-
promises[bucketName] = client
|
|
125
|
-
.createBucket({
|
|
126
|
-
Bucket: bucketName,
|
|
127
|
-
})
|
|
128
|
-
.promise()
|
|
129
|
-
await promises[bucketName]
|
|
130
|
-
delete promises[bucketName]
|
|
131
|
-
}
|
|
132
|
-
} else {
|
|
133
|
-
throw new Error("Unable to write to object store bucket.")
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
/**
|
|
139
|
-
* Uploads the contents of a file given the required parameters, useful when
|
|
140
|
-
* temp files in use (for example file uploaded as an attachment).
|
|
141
|
-
*/
|
|
142
|
-
export const upload = async ({
|
|
143
|
-
bucket: bucketName,
|
|
144
|
-
filename,
|
|
145
|
-
path,
|
|
146
|
-
type,
|
|
147
|
-
metadata,
|
|
148
|
-
}: UploadParams) => {
|
|
149
|
-
const extension = filename.split(".").pop()
|
|
150
|
-
const fileBytes = fs.readFileSync(path)
|
|
151
|
-
|
|
152
|
-
const objectStore = ObjectStore(bucketName)
|
|
153
|
-
await makeSureBucketExists(objectStore, bucketName)
|
|
154
|
-
|
|
155
|
-
let contentType = type
|
|
156
|
-
if (!contentType) {
|
|
157
|
-
contentType = extension
|
|
158
|
-
? CONTENT_TYPE_MAP[extension.toLowerCase()]
|
|
159
|
-
: CONTENT_TYPE_MAP.txt
|
|
160
|
-
}
|
|
161
|
-
const config: any = {
|
|
162
|
-
// windows file paths need to be converted to forward slashes for s3
|
|
163
|
-
Key: sanitizeKey(filename),
|
|
164
|
-
Body: fileBytes,
|
|
165
|
-
ContentType: contentType,
|
|
166
|
-
}
|
|
167
|
-
if (metadata && typeof metadata === "object") {
|
|
168
|
-
// remove any nullish keys from the metadata object, as these may be considered invalid
|
|
169
|
-
for (let key of Object.keys(metadata)) {
|
|
170
|
-
if (!metadata[key] || typeof metadata[key] !== "string") {
|
|
171
|
-
delete metadata[key]
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
config.Metadata = metadata
|
|
175
|
-
}
|
|
176
|
-
return objectStore.upload(config).promise()
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
/**
|
|
180
|
-
* Similar to the upload function but can be used to send a file stream
|
|
181
|
-
* through to the object store.
|
|
182
|
-
*/
|
|
183
|
-
export const streamUpload = async (
|
|
184
|
-
bucketName: string,
|
|
185
|
-
filename: string,
|
|
186
|
-
stream: any,
|
|
187
|
-
extra = {}
|
|
188
|
-
) => {
|
|
189
|
-
const objectStore = ObjectStore(bucketName)
|
|
190
|
-
await makeSureBucketExists(objectStore, bucketName)
|
|
191
|
-
|
|
192
|
-
// Set content type for certain known extensions
|
|
193
|
-
if (filename?.endsWith(".js")) {
|
|
194
|
-
extra = {
|
|
195
|
-
...extra,
|
|
196
|
-
ContentType: "application/javascript",
|
|
197
|
-
}
|
|
198
|
-
} else if (filename?.endsWith(".svg")) {
|
|
199
|
-
extra = {
|
|
200
|
-
...extra,
|
|
201
|
-
ContentType: "image",
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
const params = {
|
|
206
|
-
Bucket: sanitizeBucket(bucketName),
|
|
207
|
-
Key: sanitizeKey(filename),
|
|
208
|
-
Body: stream,
|
|
209
|
-
...extra,
|
|
210
|
-
}
|
|
211
|
-
return objectStore.upload(params).promise()
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
/**
|
|
215
|
-
* retrieves the contents of a file from the object store, if it is a known content type it
|
|
216
|
-
* will be converted, otherwise it will be returned as a buffer stream.
|
|
217
|
-
*/
|
|
218
|
-
export const retrieve = async (bucketName: string, filepath: string) => {
|
|
219
|
-
const objectStore = ObjectStore(bucketName)
|
|
220
|
-
const params = {
|
|
221
|
-
Bucket: sanitizeBucket(bucketName),
|
|
222
|
-
Key: sanitizeKey(filepath),
|
|
223
|
-
}
|
|
224
|
-
const response: any = await objectStore.getObject(params).promise()
|
|
225
|
-
// currently these are all strings
|
|
226
|
-
if (STRING_CONTENT_TYPES.includes(response.ContentType)) {
|
|
227
|
-
return response.Body.toString("utf8")
|
|
228
|
-
} else {
|
|
229
|
-
return response.Body
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
export const listAllObjects = async (bucketName: string, path: string) => {
|
|
234
|
-
const objectStore = ObjectStore(bucketName)
|
|
235
|
-
const list = (params: ListParams = {}) => {
|
|
236
|
-
return objectStore
|
|
237
|
-
.listObjectsV2({
|
|
238
|
-
...params,
|
|
239
|
-
Bucket: sanitizeBucket(bucketName),
|
|
240
|
-
Prefix: sanitizeKey(path),
|
|
241
|
-
})
|
|
242
|
-
.promise()
|
|
243
|
-
}
|
|
244
|
-
let isTruncated = false,
|
|
245
|
-
token,
|
|
246
|
-
objects: AWS.S3.Types.Object[] = []
|
|
247
|
-
do {
|
|
248
|
-
let params: ListParams = {}
|
|
249
|
-
if (token) {
|
|
250
|
-
params.ContinuationToken = token
|
|
251
|
-
}
|
|
252
|
-
const response = await list(params)
|
|
253
|
-
if (response.Contents) {
|
|
254
|
-
objects = objects.concat(response.Contents)
|
|
255
|
-
}
|
|
256
|
-
isTruncated = !!response.IsTruncated
|
|
257
|
-
} while (isTruncated)
|
|
258
|
-
return objects
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
/**
|
|
262
|
-
* Generate a presigned url with a default TTL of 1 hour
|
|
263
|
-
*/
|
|
264
|
-
export const getPresignedUrl = (
|
|
265
|
-
bucketName: string,
|
|
266
|
-
key: string,
|
|
267
|
-
durationSeconds: number = 3600
|
|
268
|
-
) => {
|
|
269
|
-
const objectStore = ObjectStore(bucketName, { presigning: true })
|
|
270
|
-
const params = {
|
|
271
|
-
Bucket: sanitizeBucket(bucketName),
|
|
272
|
-
Key: sanitizeKey(key),
|
|
273
|
-
Expires: durationSeconds,
|
|
274
|
-
}
|
|
275
|
-
const url = objectStore.getSignedUrl("getObject", params)
|
|
276
|
-
|
|
277
|
-
if (!env.MINIO_ENABLED) {
|
|
278
|
-
// return the full URL to the client
|
|
279
|
-
return url
|
|
280
|
-
} else {
|
|
281
|
-
// return the path only to the client
|
|
282
|
-
// use the presigned url route to ensure the static
|
|
283
|
-
// hostname will be used in the request
|
|
284
|
-
const signedUrl = new URL(url)
|
|
285
|
-
const path = signedUrl.pathname
|
|
286
|
-
const query = signedUrl.search
|
|
287
|
-
return `/files/signed${path}${query}`
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
/**
|
|
292
|
-
* Same as retrieval function but puts to a temporary file.
|
|
293
|
-
*/
|
|
294
|
-
export const retrieveToTmp = async (bucketName: string, filepath: string) => {
|
|
295
|
-
bucketName = sanitizeBucket(bucketName)
|
|
296
|
-
filepath = sanitizeKey(filepath)
|
|
297
|
-
const data = await retrieve(bucketName, filepath)
|
|
298
|
-
const outputPath = join(budibaseTempDir(), v4())
|
|
299
|
-
fs.writeFileSync(outputPath, data)
|
|
300
|
-
return outputPath
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
export const retrieveDirectory = async (bucketName: string, path: string) => {
|
|
304
|
-
let writePath = join(budibaseTempDir(), v4())
|
|
305
|
-
fs.mkdirSync(writePath)
|
|
306
|
-
const objects = await listAllObjects(bucketName, path)
|
|
307
|
-
let fullObjects = await Promise.all(
|
|
308
|
-
objects.map(obj => retrieve(bucketName, obj.Key!))
|
|
309
|
-
)
|
|
310
|
-
let count = 0
|
|
311
|
-
for (let obj of objects) {
|
|
312
|
-
const filename = obj.Key!
|
|
313
|
-
const data = fullObjects[count++]
|
|
314
|
-
const possiblePath = filename.split("/")
|
|
315
|
-
if (possiblePath.length > 1) {
|
|
316
|
-
const dirs = possiblePath.slice(0, possiblePath.length - 1)
|
|
317
|
-
fs.mkdirSync(join(writePath, ...dirs), { recursive: true })
|
|
318
|
-
}
|
|
319
|
-
fs.writeFileSync(join(writePath, ...possiblePath), data)
|
|
320
|
-
}
|
|
321
|
-
return writePath
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
/**
|
|
325
|
-
* Delete a single file.
|
|
326
|
-
*/
|
|
327
|
-
export const deleteFile = async (bucketName: string, filepath: string) => {
|
|
328
|
-
const objectStore = ObjectStore(bucketName)
|
|
329
|
-
await makeSureBucketExists(objectStore, bucketName)
|
|
330
|
-
const params = {
|
|
331
|
-
Bucket: bucketName,
|
|
332
|
-
Key: sanitizeKey(filepath),
|
|
333
|
-
}
|
|
334
|
-
return objectStore.deleteObject(params).promise()
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
export const deleteFiles = async (bucketName: string, filepaths: string[]) => {
|
|
338
|
-
const objectStore = ObjectStore(bucketName)
|
|
339
|
-
await makeSureBucketExists(objectStore, bucketName)
|
|
340
|
-
const params = {
|
|
341
|
-
Bucket: bucketName,
|
|
342
|
-
Delete: {
|
|
343
|
-
Objects: filepaths.map((path: any) => ({ Key: sanitizeKey(path) })),
|
|
344
|
-
},
|
|
345
|
-
}
|
|
346
|
-
return objectStore.deleteObjects(params).promise()
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
/**
|
|
350
|
-
* Delete a path, including everything within.
|
|
351
|
-
*/
|
|
352
|
-
export const deleteFolder = async (
|
|
353
|
-
bucketName: string,
|
|
354
|
-
folder: string
|
|
355
|
-
): Promise<any> => {
|
|
356
|
-
bucketName = sanitizeBucket(bucketName)
|
|
357
|
-
folder = sanitizeKey(folder)
|
|
358
|
-
const client = ObjectStore(bucketName)
|
|
359
|
-
const listParams = {
|
|
360
|
-
Bucket: bucketName,
|
|
361
|
-
Prefix: folder,
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
const existingObjectsResponse = await client.listObjects(listParams).promise()
|
|
365
|
-
if (existingObjectsResponse.Contents?.length === 0) {
|
|
366
|
-
return
|
|
367
|
-
}
|
|
368
|
-
const deleteParams: any = {
|
|
369
|
-
Bucket: bucketName,
|
|
370
|
-
Delete: {
|
|
371
|
-
Objects: [],
|
|
372
|
-
},
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
existingObjectsResponse.Contents?.forEach((content: any) => {
|
|
376
|
-
deleteParams.Delete.Objects.push({ Key: content.Key })
|
|
377
|
-
})
|
|
378
|
-
|
|
379
|
-
const deleteResponse = await client.deleteObjects(deleteParams).promise()
|
|
380
|
-
// can only empty 1000 items at once
|
|
381
|
-
if (deleteResponse.Deleted?.length === 1000) {
|
|
382
|
-
return deleteFolder(bucketName, folder)
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
export const uploadDirectory = async (
|
|
387
|
-
bucketName: string,
|
|
388
|
-
localPath: string,
|
|
389
|
-
bucketPath: string
|
|
390
|
-
) => {
|
|
391
|
-
bucketName = sanitizeBucket(bucketName)
|
|
392
|
-
let uploads = []
|
|
393
|
-
const files = fs.readdirSync(localPath, { withFileTypes: true })
|
|
394
|
-
for (let file of files) {
|
|
395
|
-
const path = sanitizeKey(join(bucketPath, file.name))
|
|
396
|
-
const local = join(localPath, file.name)
|
|
397
|
-
if (file.isDirectory()) {
|
|
398
|
-
uploads.push(uploadDirectory(bucketName, local, path))
|
|
399
|
-
} else {
|
|
400
|
-
uploads.push(streamUpload(bucketName, path, fs.createReadStream(local)))
|
|
401
|
-
}
|
|
402
|
-
}
|
|
403
|
-
await Promise.all(uploads)
|
|
404
|
-
return files
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
export const downloadTarballDirect = async (
|
|
408
|
-
url: string,
|
|
409
|
-
path: string,
|
|
410
|
-
headers = {}
|
|
411
|
-
) => {
|
|
412
|
-
path = sanitizeKey(path)
|
|
413
|
-
const response = await fetch(url, { headers })
|
|
414
|
-
if (!response.ok) {
|
|
415
|
-
throw new Error(`unexpected response ${response.statusText}`)
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
await streamPipeline(response.body, zlib.createUnzip(), tar.extract(path))
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
export const downloadTarball = async (
|
|
422
|
-
url: string,
|
|
423
|
-
bucketName: string,
|
|
424
|
-
path: string
|
|
425
|
-
) => {
|
|
426
|
-
bucketName = sanitizeBucket(bucketName)
|
|
427
|
-
path = sanitizeKey(path)
|
|
428
|
-
const response = await fetch(url)
|
|
429
|
-
if (!response.ok) {
|
|
430
|
-
throw new Error(`unexpected response ${response.statusText}`)
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
const tmpPath = join(budibaseTempDir(), path)
|
|
434
|
-
await streamPipeline(response.body, zlib.createUnzip(), tar.extract(tmpPath))
|
|
435
|
-
if (!env.isTest() && env.SELF_HOSTED) {
|
|
436
|
-
await uploadDirectory(bucketName, tmpPath, path)
|
|
437
|
-
}
|
|
438
|
-
// return the temporary path incase there is a use for it
|
|
439
|
-
return tmpPath
|
|
440
|
-
}
|
package/src/objectStore/utils.ts
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { join } from "path"
|
|
2
|
-
import { tmpdir } from "os"
|
|
3
|
-
import fs from "fs"
|
|
4
|
-
import env from "../environment"
|
|
5
|
-
|
|
6
|
-
/****************************************************
|
|
7
|
-
* NOTE: When adding a new bucket - name *
|
|
8
|
-
* sure that S3 usages (like budibase-infra) *
|
|
9
|
-
* have been updated to have a unique bucket name. *
|
|
10
|
-
****************************************************/
|
|
11
|
-
// can't be an enum - only numbers can be used for computed types
|
|
12
|
-
export const ObjectStoreBuckets = {
|
|
13
|
-
BACKUPS: env.BACKUPS_BUCKET_NAME,
|
|
14
|
-
APPS: env.APPS_BUCKET_NAME,
|
|
15
|
-
TEMPLATES: env.TEMPLATES_BUCKET_NAME,
|
|
16
|
-
GLOBAL: env.GLOBAL_BUCKET_NAME,
|
|
17
|
-
PLUGINS: env.PLUGIN_BUCKET_NAME,
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const bbTmp = join(tmpdir(), ".budibase")
|
|
21
|
-
if (!fs.existsSync(bbTmp)) {
|
|
22
|
-
fs.mkdirSync(bbTmp)
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export function budibaseTempDir() {
|
|
26
|
-
return bbTmp
|
|
27
|
-
}
|
package/src/platform/index.ts
DELETED
package/src/platform/tenants.ts
DELETED
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
import { StaticDatabases } from "../constants"
|
|
2
|
-
import { getPlatformDB } from "./platformDb"
|
|
3
|
-
import { LockName, LockOptions, LockType, Tenants } from "@budibase/types"
|
|
4
|
-
import * as locks from "../redis/redlockImpl"
|
|
5
|
-
|
|
6
|
-
const TENANT_DOC = StaticDatabases.PLATFORM_INFO.docs.tenants
|
|
7
|
-
|
|
8
|
-
export const tenacyLockOptions: LockOptions = {
|
|
9
|
-
type: LockType.DEFAULT,
|
|
10
|
-
name: LockName.UPDATE_TENANTS_DOC,
|
|
11
|
-
ttl: 10 * 1000, // auto expire after 10 seconds
|
|
12
|
-
systemLock: true,
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
// READ
|
|
16
|
-
|
|
17
|
-
export async function getTenantIds(): Promise<string[]> {
|
|
18
|
-
const tenants = await getTenants()
|
|
19
|
-
return tenants.tenantIds
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
async function getTenants(): Promise<Tenants> {
|
|
23
|
-
const db = getPlatformDB()
|
|
24
|
-
let tenants: Tenants
|
|
25
|
-
|
|
26
|
-
try {
|
|
27
|
-
tenants = await db.get(TENANT_DOC)
|
|
28
|
-
} catch (e: any) {
|
|
29
|
-
// doesn't exist yet - create
|
|
30
|
-
if (e.status === 404) {
|
|
31
|
-
tenants = await createTenantsDoc()
|
|
32
|
-
} else {
|
|
33
|
-
throw e
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
return tenants
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export async function exists(tenantId: string) {
|
|
41
|
-
const tenants = await getTenants()
|
|
42
|
-
return tenants.tenantIds.indexOf(tenantId) !== -1
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// CREATE / UPDATE
|
|
46
|
-
|
|
47
|
-
function newTenantsDoc(): Tenants {
|
|
48
|
-
return {
|
|
49
|
-
_id: TENANT_DOC,
|
|
50
|
-
tenantIds: [],
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
async function createTenantsDoc(): Promise<Tenants> {
|
|
55
|
-
const db = getPlatformDB()
|
|
56
|
-
let tenants = newTenantsDoc()
|
|
57
|
-
|
|
58
|
-
try {
|
|
59
|
-
const response = await db.put(tenants)
|
|
60
|
-
tenants._rev = response.rev
|
|
61
|
-
} catch (e: any) {
|
|
62
|
-
// don't throw 409 is doc has already been created
|
|
63
|
-
if (e.status === 409) {
|
|
64
|
-
return db.get(TENANT_DOC)
|
|
65
|
-
}
|
|
66
|
-
throw e
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
return tenants
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
export async function addTenant(tenantId: string) {
|
|
73
|
-
const db = getPlatformDB()
|
|
74
|
-
|
|
75
|
-
// use a lock as tenant creation is conflict prone
|
|
76
|
-
await locks.doWithLock(tenacyLockOptions, async () => {
|
|
77
|
-
const tenants = await getTenants()
|
|
78
|
-
|
|
79
|
-
// write the new tenant if it doesn't already exist
|
|
80
|
-
if (tenants.tenantIds.indexOf(tenantId) === -1) {
|
|
81
|
-
tenants.tenantIds.push(tenantId)
|
|
82
|
-
await db.put(tenants)
|
|
83
|
-
}
|
|
84
|
-
})
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// DELETE
|
|
88
|
-
|
|
89
|
-
export async function removeTenant(tenantId: string) {
|
|
90
|
-
try {
|
|
91
|
-
await locks.doWithLock(tenacyLockOptions, async () => {
|
|
92
|
-
const db = getPlatformDB()
|
|
93
|
-
const tenants = await getTenants()
|
|
94
|
-
tenants.tenantIds = tenants.tenantIds.filter(id => id !== tenantId)
|
|
95
|
-
await db.put(tenants)
|
|
96
|
-
})
|
|
97
|
-
} catch (err) {
|
|
98
|
-
console.error(`Error removing tenant ${tenantId} from info db`, err)
|
|
99
|
-
throw err
|
|
100
|
-
}
|
|
101
|
-
}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { structures } from "../../../tests"
|
|
2
|
-
import { DBTestConfiguration } from "../../../tests/extra"
|
|
3
|
-
import * as tenants from "../tenants"
|
|
4
|
-
|
|
5
|
-
describe("tenants", () => {
|
|
6
|
-
const config = new DBTestConfiguration()
|
|
7
|
-
|
|
8
|
-
describe("addTenant", () => {
|
|
9
|
-
it("concurrently adds multiple tenants safely", async () => {
|
|
10
|
-
const tenant1 = structures.tenant.id()
|
|
11
|
-
const tenant2 = structures.tenant.id()
|
|
12
|
-
const tenant3 = structures.tenant.id()
|
|
13
|
-
|
|
14
|
-
await Promise.all([
|
|
15
|
-
tenants.addTenant(tenant1),
|
|
16
|
-
tenants.addTenant(tenant2),
|
|
17
|
-
tenants.addTenant(tenant3),
|
|
18
|
-
])
|
|
19
|
-
|
|
20
|
-
const tenantIds = await tenants.getTenantIds()
|
|
21
|
-
expect(tenantIds.includes(tenant1)).toBe(true)
|
|
22
|
-
expect(tenantIds.includes(tenant2)).toBe(true)
|
|
23
|
-
expect(tenantIds.includes(tenant3)).toBe(true)
|
|
24
|
-
})
|
|
25
|
-
})
|
|
26
|
-
})
|
package/src/platform/users.ts
DELETED
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
import { getPlatformDB } from "./platformDb"
|
|
2
|
-
import { DEFAULT_TENANT_ID } from "../constants"
|
|
3
|
-
import env from "../environment"
|
|
4
|
-
import {
|
|
5
|
-
PlatformUser,
|
|
6
|
-
PlatformUserByEmail,
|
|
7
|
-
PlatformUserById,
|
|
8
|
-
User,
|
|
9
|
-
} from "@budibase/types"
|
|
10
|
-
|
|
11
|
-
// READ
|
|
12
|
-
|
|
13
|
-
export async function lookupTenantId(userId: string) {
|
|
14
|
-
if (!env.MULTI_TENANCY) {
|
|
15
|
-
return DEFAULT_TENANT_ID
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
const user = await getUserDoc(userId)
|
|
19
|
-
return user.tenantId
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
async function getUserDoc(emailOrId: string): Promise<PlatformUser> {
|
|
23
|
-
const db = getPlatformDB()
|
|
24
|
-
return db.get(emailOrId)
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// CREATE
|
|
28
|
-
|
|
29
|
-
function newUserIdDoc(id: string, tenantId: string): PlatformUserById {
|
|
30
|
-
return {
|
|
31
|
-
_id: id,
|
|
32
|
-
tenantId,
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
function newUserEmailDoc(
|
|
37
|
-
userId: string,
|
|
38
|
-
email: string,
|
|
39
|
-
tenantId: string
|
|
40
|
-
): PlatformUserByEmail {
|
|
41
|
-
return {
|
|
42
|
-
_id: email,
|
|
43
|
-
userId,
|
|
44
|
-
tenantId,
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Add a new user id or email doc if it doesn't exist.
|
|
50
|
-
*/
|
|
51
|
-
async function addUserDoc(emailOrId: string, newDocFn: () => PlatformUser) {
|
|
52
|
-
const db = getPlatformDB()
|
|
53
|
-
let user: PlatformUser
|
|
54
|
-
|
|
55
|
-
try {
|
|
56
|
-
await db.get(emailOrId)
|
|
57
|
-
} catch (e: any) {
|
|
58
|
-
if (e.status === 404) {
|
|
59
|
-
user = newDocFn()
|
|
60
|
-
await db.put(user)
|
|
61
|
-
} else {
|
|
62
|
-
throw e
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
export async function addUser(tenantId: string, userId: string, email: string) {
|
|
68
|
-
await Promise.all([
|
|
69
|
-
addUserDoc(userId, () => newUserIdDoc(userId, tenantId)),
|
|
70
|
-
addUserDoc(email, () => newUserEmailDoc(userId, email, tenantId)),
|
|
71
|
-
])
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// DELETE
|
|
75
|
-
|
|
76
|
-
export async function removeUser(user: User) {
|
|
77
|
-
const db = getPlatformDB()
|
|
78
|
-
const keys = [user._id!, user.email]
|
|
79
|
-
const userDocs = await db.allDocs({
|
|
80
|
-
keys,
|
|
81
|
-
include_docs: true,
|
|
82
|
-
})
|
|
83
|
-
const toDelete = userDocs.rows.map((row: any) => {
|
|
84
|
-
return {
|
|
85
|
-
...row.doc,
|
|
86
|
-
_deleted: true,
|
|
87
|
-
}
|
|
88
|
-
})
|
|
89
|
-
await db.bulkDocs(toDelete)
|
|
90
|
-
}
|
package/src/plugin/index.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from "./utils"
|