diff --git a/.github/workflows/deploy-cloud.yaml b/.github/workflows/deploy-cloud.yaml index d54e6c9c68..afb28d42be 100644 --- a/.github/workflows/deploy-cloud.yaml +++ b/.github/workflows/deploy-cloud.yaml @@ -38,6 +38,17 @@ jobs: fi echo "RELEASE_VERSION=$release_version" >> $GITHUB_ENV + - name: Tag and release Proxy service docker image + run: | + docker login -u $DOCKER_USER -p $DOCKER_PASSWORD + yarn build:docker:proxy:prod + docker tag budibase/proxy:$release_tag budibase/proxy:$PROD_TAG + docker push budibase/proxy:$PROD_TAG + env: + DOCKER_USER: ${{ secrets.DOCKER_USERNAME }} + DOCKER_PASSWORD: ${{ secrets.DOCKER_API_KEY }} + PROD_TAG: k8s + - name: Configure AWS Credentials uses: aws-actions/configure-aws-credentials@v1 with: diff --git a/.github/workflows/deploy-preprod.yml b/.github/workflows/deploy-preprod.yml index 10fadc36c5..7abe3bd533 100644 --- a/.github/workflows/deploy-preprod.yml +++ b/.github/workflows/deploy-preprod.yml @@ -23,12 +23,24 @@ jobs: aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} aws-region: eu-west-1 + - name: Get the latest budibase release version id: version run: | release_version=$(cat lerna.json | jq -r '.version') echo "RELEASE_VERSION=$release_version" >> $GITHUB_ENV + - name: Tag and release Proxy service docker image + run: | + docker login -u $DOCKER_USER -p $DOCKER_PASSWORD + yarn build:docker:proxy:preprod + docker tag budibase/proxy:$release_tag budibase/proxy:$PREPROD_TAG + docker push budibase/proxy:$PREPROD_TAG + env: + DOCKER_USER: ${{ secrets.DOCKER_USERNAME }} + DOCKER_PASSWORD: ${{ secrets.DOCKER_API_KEY }} + PREPROD_TAG: k8s-preprod + - name: Pull values.yaml from budibase-infra run: | curl -H "Authorization: token ${{ secrets.GH_PERSONAL_TOKEN }}" \ diff --git a/hosting/nginx.prod.conf.hbs b/hosting/nginx.prod.conf.hbs index f446c928fb..ac60d367e7 100644 --- a/hosting/nginx.prod.conf.hbs +++ b/hosting/nginx.prod.conf.hbs @@ -19,13 +19,7 @@ http { tcp_nodelay on; server_tokens off; types_hash_max_size 2048; - {{#if compose}} - resolver 127.0.0.11 ipv6=off; - {{/if}} - {{#if k8s}} - resolver kube-dns.kube-system.svc.cluster.local valid=10s; - {{/if}} - + resolver {{ resolver }} valid=10s ipv6=off; # buffering client_body_buffer_size 1K; @@ -55,7 +49,7 @@ http { add_header X-Frame-Options SAMEORIGIN always; add_header X-Content-Type-Options nosniff always; add_header X-XSS-Protection "1; mode=block" always; - add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://cdn.budi.live https://js.intercomcdn.com https://widget.intercom.io; style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net https://fonts.googleapis.com https://rsms.me https://maxcdn.bootstrapcdn.com; object-src 'none'; base-uri 'self'; connect-src 'self' https://api-iam.intercom.io https://app.posthog.com wss://nexus-websocket-a.intercom.io; font-src 'self' data https://cdn.jsdelivr.net https://fonts.gstatic.com https://rsms.me https://maxcdn.bootstrapcdn.com; frame-src 'self'; img-src http: https: data; manifest-src 'self'; media-src 'self'; worker-src 'none';" always; + add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://cdn.budi.live https://js.intercomcdn.com https://widget.intercom.io; style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net https://fonts.googleapis.com https://rsms.me https://maxcdn.bootstrapcdn.com; object-src 'none'; base-uri 'self'; connect-src 'self' https://api-iam.intercom.io https://app.posthog.com wss://nexus-websocket-a.intercom.io; font-src 'self' data https://cdn.jsdelivr.net https://fonts.gstatic.com https://rsms.me https://maxcdn.bootstrapcdn.com; frame-src 'self' https:; img-src http: https: data; manifest-src 'self'; media-src 'self'; worker-src 'none';" always; # upstreams set $apps {{ apps }}; diff --git a/hosting/proxy/nginx.conf b/hosting/proxy/nginx.conf deleted file mode 100644 index 95b06d4fff..0000000000 --- a/hosting/proxy/nginx.conf +++ /dev/null @@ -1,145 +0,0 @@ -user nginx; -error_log /var/log/nginx/error.log debug; -pid /var/run/nginx.pid; -worker_processes auto; -worker_rlimit_nofile 33282; - -events { - worker_connections 1024; -} - -http { - limit_req_zone $binary_remote_addr zone=ratelimit:10m rate=20r/s; - include /etc/nginx/mime.types; - default_type application/octet-stream; - charset utf-8; - sendfile on; - tcp_nopush on; - tcp_nodelay on; - server_tokens off; - types_hash_max_size 2048; - - # buffering - client_body_buffer_size 1K; - client_header_buffer_size 1k; - client_max_body_size 1k; - ignore_invalid_headers off; - - - log_format main '$remote_addr - $remote_user [$time_local] "$request" ' - '$status $body_bytes_sent "$http_referer" ' - '"$http_user_agent" "$http_x_forwarded_for"'; - - map $http_upgrade $connection_upgrade { - default "upgrade"; - } - - server { - listen 10000 default_server; - listen [::]:10000 default_server; - server_name _; - client_max_body_size 1000m; - ignore_invalid_headers off; - proxy_buffering off; - port_in_redirect off; - - # Security Headers - add_header X-Frame-Options SAMEORIGIN always; - add_header X-Content-Type-Options nosniff always; - add_header X-XSS-Protection "1; mode=block" always; - add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://cdn.budi.live https://js.intercomcdn.com https://widget.intercom.io; style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net https://fonts.googleapis.com https://rsms.me; object-src 'none'; base-uri 'self'; connect-src 'self' https://api-iam.intercom.io https://app.posthog.com wss://nexus-websocket-a.intercom.io; font-src 'self' data: https://cdn.jsdelivr.net https://fonts.gstatic.com https://rsms.me; frame-src 'self'; img-src http: https: data:; manifest-src 'self'; media-src 'self'; worker-src 'none';" always; - - location /app { - proxy_pass http://app-service:4002; - rewrite ^/app/(.*)$ /$1 break; - } - - location = / { - port_in_redirect off; - proxy_pass http://app-service:4002; - } - - location = /v1/update { - proxy_pass http://watchtower-service:8080; - } - - location /builder/ { - port_in_redirect off; - proxy_http_version 1.1; - proxy_set_header Connection $connection_upgrade; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_pass http://app-service:4002; - } - - location ~ ^/(builder|app_) { - port_in_redirect off; - proxy_http_version 1.1; - proxy_set_header Connection $connection_upgrade; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_pass http://app-service:4002; - } - - location ~ ^/api/(system|admin|global)/ { - proxy_pass http://worker-service:4003; - } - - location /worker/ { - proxy_pass http://worker-service:4003; - rewrite ^/worker/(.*)$ /$1 break; - } - - location /api/ { - # calls to the API are rate limited with bursting - limit_req zone=ratelimit burst=20 nodelay; - - # 120s timeout on API requests - proxy_read_timeout 120s; - proxy_connect_timeout 120s; - proxy_send_timeout 120s; - - proxy_http_version 1.1; - proxy_set_header Connection $connection_upgrade; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - - proxy_pass http://app-service:4002; - } - - location /db/ { - proxy_pass http://couchdb-service:5984; - rewrite ^/db/(.*)$ /$1 break; - } - - location / { - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - proxy_set_header Host $http_host; - - proxy_connect_timeout 300; - proxy_http_version 1.1; - proxy_set_header Connection ""; - chunked_transfer_encoding off; - proxy_pass http://minio-service:9000; - } - - client_header_timeout 60; - client_body_timeout 60; - keepalive_timeout 60; - - # gzip - gzip on; - gzip_vary on; - gzip_proxied any; - gzip_comp_level 6; - gzip_types text/plain text/css text/xml application/json application/javascript application/rss+xml application/atom+xml image/svg+xml; - } -} \ No newline at end of file diff --git a/lerna.json b/lerna.json index 07b77404de..34b317589f 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "1.0.79-alpha.7", + "version": "1.0.80-alpha.1", "npmClient": "yarn", "packages": [ "packages/*" diff --git a/package.json b/package.json index 626daf8b51..69c7967409 100644 --- a/package.json +++ b/package.json @@ -47,9 +47,9 @@ "build:specs": "lerna run specs", "build:docker": "lerna run build:docker && npm run build:docker:proxy:compose && cd hosting/scripts/linux/ && ./release-to-docker-hub.sh $BUDIBASE_RELEASE_VERSION && cd -", "build:docker:proxy": "docker build hosting/proxy -t proxy-service", - "build:docker:proxy:compose": "lerna run generate:proxy:compose && npm run build:docker:proxy", - "build:docker:proxy:preprod": "lerna run generate:proxy:preprod && npm run build:docker:proxy", - "build:docker:proxy:prod": "lerna run generate:proxy:prod && npm run build:docker:proxy", + "build:docker:proxy:compose": "node scripts/proxy/generateProxyConfig compose && npm run build:docker:proxy", + "build:docker:proxy:preprod": "node scripts/proxy/generateProxyConfig preprod && npm run build:docker:proxy", + "build:docker:proxy:prod": "node scripts/proxy/generateProxyConfig prod && npm run build:docker:proxy", "build:docker:selfhost": "lerna run build:docker && cd hosting/scripts/linux/ && ./release-to-docker-hub.sh latest && cd -", "build:docker:develop": "node scripts/pinVersions && lerna run build:docker && npm run build:docker:proxy:compose && cd hosting/scripts/linux/ && ./release-to-docker-hub.sh develop && cd -", "build:docker:airgap": "node hosting/scripts/airgapped/airgappedDockerBuild", diff --git a/packages/backend-core/package.json b/packages/backend-core/package.json index 8b52691512..77f75cf8b9 100644 --- a/packages/backend-core/package.json +++ b/packages/backend-core/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/backend-core", - "version": "1.0.79-alpha.7", + "version": "1.0.80-alpha.1", "description": "Budibase backend core libraries used in server and worker", "main": "src/index.js", "author": "Budibase", diff --git a/packages/bbui/package.json b/packages/bbui/package.json index 8c822980cf..107f36362c 100644 --- a/packages/bbui/package.json +++ b/packages/bbui/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/bbui", "description": "A UI solution used in the different Budibase projects.", - "version": "1.0.79-alpha.7", + "version": "1.0.80-alpha.1", "license": "MPL-2.0", "svelte": "src/index.js", "module": "dist/bbui.es.js", @@ -38,7 +38,7 @@ ], "dependencies": { "@adobe/spectrum-css-workflow-icons": "^1.2.1", - "@budibase/string-templates": "^1.0.79-alpha.7", + "@budibase/string-templates": "^1.0.80-alpha.1", "@spectrum-css/actionbutton": "^1.0.1", "@spectrum-css/actiongroup": "^1.0.1", "@spectrum-css/avatar": "^3.0.2", diff --git a/packages/builder/package.json b/packages/builder/package.json index 33518612e5..4ab45385fb 100644 --- a/packages/builder/package.json +++ b/packages/builder/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/builder", - "version": "1.0.79-alpha.7", + "version": "1.0.80-alpha.1", "license": "GPL-3.0", "private": true, "scripts": { @@ -65,10 +65,10 @@ } }, "dependencies": { - "@budibase/bbui": "^1.0.79-alpha.7", - "@budibase/client": "^1.0.79-alpha.7", - "@budibase/frontend-core": "^1.0.79-alpha.7", - "@budibase/string-templates": "^1.0.79-alpha.7", + "@budibase/bbui": "^1.0.80-alpha.1", + "@budibase/client": "^1.0.80-alpha.1", + "@budibase/frontend-core": "^1.0.80-alpha.1", + "@budibase/string-templates": "^1.0.80-alpha.1", "@sentry/browser": "5.19.1", "@spectrum-css/page": "^3.0.1", "@spectrum-css/vars": "^3.0.1", diff --git a/packages/builder/src/builderStore/componentUtils.js b/packages/builder/src/builderStore/componentUtils.js index 557d83a00c..2ad7e82075 100644 --- a/packages/builder/src/builderStore/componentUtils.js +++ b/packages/builder/src/builderStore/componentUtils.js @@ -3,7 +3,7 @@ import { Helpers } from "@budibase/bbui" import { decodeJSBinding, encodeJSBinding, - findAllBindings, + findHBSBlocks, } from "@budibase/string-templates" /** @@ -191,7 +191,7 @@ export const makeComponentUnique = component => { children = children.replace(new RegExp(oldId, "g"), newId) // Replace all instances of this ID in child JS bindings - const bindings = findAllBindings(children) + const bindings = findHBSBlocks(children) bindings.forEach(binding => { // JSON.stringify will have escaped double quotes, so we need // to account for that diff --git a/packages/builder/src/components/design/PropertiesPanel/ComponentSettingsSection.svelte b/packages/builder/src/components/design/PropertiesPanel/ComponentSettingsSection.svelte index 88455fb003..a043cca619 100644 --- a/packages/builder/src/components/design/PropertiesPanel/ComponentSettingsSection.svelte +++ b/packages/builder/src/components/design/PropertiesPanel/ComponentSettingsSection.svelte @@ -7,6 +7,7 @@ import RoleSelect from "./PropertyControls/RoleSelect.svelte" import ResetFieldsButton from "./PropertyControls/ResetFieldsButton.svelte" import { getComponentForSettingType } from "./PropertyControls/componentSettings" + import { Utils } from "@budibase/frontend-core" export let componentDefinition export let componentInstance @@ -40,13 +41,13 @@ ] } - const updateProp = async (key, value) => { + const updateProp = Utils.sequential(async (key, value) => { try { await store.actions.components.updateProp(key, value) } catch (error) { notifications.error("Error updating component prop") } - } + }) const canRenderControl = setting => { const control = getComponentForSettingType(setting?.type) diff --git a/packages/cli/package.json b/packages/cli/package.json index 75a72fa193..23509146d2 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/cli", - "version": "1.0.79-alpha.7", + "version": "1.0.80-alpha.1", "description": "Budibase CLI, for developers, self hosting and migrations.", "main": "src/index.js", "bin": { diff --git a/packages/client/package.json b/packages/client/package.json index c776e3f698..ff7f65bce6 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/client", - "version": "1.0.79-alpha.7", + "version": "1.0.80-alpha.1", "license": "MPL-2.0", "module": "dist/budibase-client.js", "main": "dist/budibase-client.js", @@ -19,9 +19,9 @@ "dev:builder": "rollup -cw" }, "dependencies": { - "@budibase/bbui": "^1.0.79-alpha.7", - "@budibase/frontend-core": "^1.0.79-alpha.7", - "@budibase/string-templates": "^1.0.79-alpha.7", + "@budibase/bbui": "^1.0.80-alpha.1", + "@budibase/frontend-core": "^1.0.80-alpha.1", + "@budibase/string-templates": "^1.0.80-alpha.1", "@spectrum-css/button": "^3.0.3", "@spectrum-css/card": "^3.0.3", "@spectrum-css/divider": "^1.0.3", diff --git a/packages/client/src/components/app/forms/optionsParser.js b/packages/client/src/components/app/forms/optionsParser.js index dd37989be7..e670ccb076 100644 --- a/packages/client/src/components/app/forms/optionsParser.js +++ b/packages/client/src/components/app/forms/optionsParser.js @@ -17,7 +17,7 @@ export const getOptions = ( dataProvider?.rows?.forEach(row => { const value = row?.[valueColumn] - if (value) { + if (value != null) { const label = row[labelColumn] || value optionsSet[value] = { value, label } } @@ -30,7 +30,7 @@ export const getOptions = ( let optionsSet = {} dataProvider?.rows?.forEach(row => { const value = row?.[valueColumn] - if (value) { + if (value != null) { const label = row[labelColumn] || value optionsSet[value] = { value, label } } diff --git a/packages/frontend-core/package.json b/packages/frontend-core/package.json index fe73177cbb..eeb6bfb1f2 100644 --- a/packages/frontend-core/package.json +++ b/packages/frontend-core/package.json @@ -1,12 +1,12 @@ { "name": "@budibase/frontend-core", - "version": "1.0.79-alpha.7", + "version": "1.0.80-alpha.1", "description": "Budibase frontend core libraries used in builder and client", "author": "Budibase", "license": "MPL-2.0", "svelte": "src/index.js", "dependencies": { - "@budibase/bbui": "^1.0.79-alpha.7", + "@budibase/bbui": "^1.0.80-alpha.1", "lodash": "^4.17.21", "svelte": "^3.46.2" } diff --git a/packages/frontend-core/src/api/other.js b/packages/frontend-core/src/api/other.js index e7b446c181..71ea19ccce 100644 --- a/packages/frontend-core/src/api/other.js +++ b/packages/frontend-core/src/api/other.js @@ -30,9 +30,11 @@ export const buildOtherEndpoints = API => ({ * Gets the version of the installed Budibase environment. */ getBudibaseVersion: async () => { - return await API.get({ - url: "/api/dev/version", - }).version + return ( + await API.get({ + url: "/api/dev/version", + }) + ).version }, /** diff --git a/packages/frontend-core/src/index.js b/packages/frontend-core/src/index.js index 53822fdfb4..aecca81cda 100644 --- a/packages/frontend-core/src/index.js +++ b/packages/frontend-core/src/index.js @@ -1,7 +1,5 @@ export { createAPIClient } from "./api" -export { createLocalStorageStore } from "./stores/localStorage" export { fetchData } from "./fetch/fetchData" export * as Constants from "./constants" -export * as LuceneUtils from "./utils/lucene" -export * as JSONUtils from "./utils/json" -export * as CookieUtils from "./utils/cookies" +export * from "./stores" +export * from "./utils" diff --git a/packages/frontend-core/src/stores/index.js b/packages/frontend-core/src/stores/index.js new file mode 100644 index 0000000000..9766da43e3 --- /dev/null +++ b/packages/frontend-core/src/stores/index.js @@ -0,0 +1 @@ +export { createLocalStorageStore } from "./localStorage" diff --git a/packages/frontend-core/src/utils/index.js b/packages/frontend-core/src/utils/index.js new file mode 100644 index 0000000000..6755940289 --- /dev/null +++ b/packages/frontend-core/src/utils/index.js @@ -0,0 +1,4 @@ +export * as LuceneUtils from "./lucene" +export * as JSONUtils from "./json" +export * as CookieUtils from "./cookies" +export * as Utils from "./utils" diff --git a/packages/frontend-core/src/utils/utils.js b/packages/frontend-core/src/utils/utils.js new file mode 100644 index 0000000000..afa88a0624 --- /dev/null +++ b/packages/frontend-core/src/utils/utils.js @@ -0,0 +1,17 @@ +/** + * Utility to wrap an async function and ensure all invocations happen + * sequentially. + * @param fn the async function to run + * @return {Promise} a sequential version of the function + */ +export const sequential = fn => { + let promise + return async (...params) => { + if (promise) { + await promise + } + promise = fn(...params) + await promise + promise = null + } +} diff --git a/packages/server/__mocks__/mysql2/promise.ts b/packages/server/__mocks__/mysql2/promise.ts new file mode 100644 index 0000000000..8a8fb7fcf0 --- /dev/null +++ b/packages/server/__mocks__/mysql2/promise.ts @@ -0,0 +1,17 @@ +module MySQLMock { + const mysql: any = {} + + const client = { + connect: jest.fn(), + end: jest.fn(), + query: jest.fn(async () => { + return [[]] + }), + } + + mysql.createConnection = jest.fn(async () => { + return client + }) + + module.exports = mysql +} diff --git a/packages/server/package.json b/packages/server/package.json index 43cf9b9dbe..6636858f9c 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/server", "email": "hi@budibase.com", - "version": "1.0.79-alpha.7", + "version": "1.0.80-alpha.1", "description": "Budibase Web Server", "main": "src/index.ts", "repository": { @@ -21,9 +21,6 @@ "dev:stack:down": "node scripts/dev/manage.js down", "dev:stack:nuke": "node scripts/dev/manage.js nuke", "dev:builder": "yarn run dev:stack:up && nodemon", - "generate:proxy:compose": "node scripts/proxy/generateProxyConfig compose", - "generate:proxy:preprod": "node scripts/proxy/generateProxyConfig preprod", - "generate:proxy:prod": "node scripts/proxy/generateProxyConfig prod", "format": "prettier --config ../../.prettierrc.json 'src/**/*.ts' --write", "specs": "node specs/generate.js && openapi-typescript specs/openapi.yaml --output src/definitions/openapi.ts", "lint": "eslint --fix src/", @@ -74,9 +71,9 @@ "license": "GPL-3.0", "dependencies": { "@apidevtools/swagger-parser": "^10.0.3", - "@budibase/backend-core": "^1.0.79-alpha.7", - "@budibase/client": "^1.0.79-alpha.7", - "@budibase/string-templates": "^1.0.79-alpha.7", + "@budibase/backend-core": "^1.0.80-alpha.1", + "@budibase/client": "^1.0.80-alpha.1", + "@budibase/string-templates": "^1.0.80-alpha.1", "@bull-board/api": "^3.7.0", "@bull-board/koa": "^3.7.0", "@elastic/elasticsearch": "7.10.0", @@ -111,6 +108,7 @@ "koa-send": "5.0.0", "koa-session": "5.12.0", "koa-static": "5.0.0", + "koa2-ratelimit": "^1.1.0", "lodash": "4.17.21", "memorystream": "^0.3.1", "mongodb": "3.6.3", @@ -126,6 +124,7 @@ "pouchdb-all-dbs": "1.0.2", "pouchdb-find": "^7.2.2", "pouchdb-replication-stream": "1.2.9", + "redis": "4", "server-destroy": "1.0.1", "svelte": "^3.38.2", "swagger-parser": "^10.0.3", @@ -151,6 +150,7 @@ "@types/koa-router": "^7.4.2", "@types/node": "^15.12.4", "@types/oracledb": "^5.2.1", + "@types/redis": "^4.0.11", "@typescript-eslint/parser": "4.28.0", "apidoc": "^0.50.2", "babel-jest": "^27.0.2", diff --git a/packages/server/scripts/integrations/oracle/oracle.md b/packages/server/scripts/integrations/oracle/oracle.md index 6c2d7a9252..58d2a7dfbf 100644 --- a/packages/server/scripts/integrations/oracle/oracle.md +++ b/packages/server/scripts/integrations/oracle/oracle.md @@ -8,9 +8,9 @@ To install oracle express edition simply run `docker-compose up` -- A single instance pluggable database (PDB) will be created named `xepdb` +- A single instance pluggable database (PDB) will be created named `xepdb1` - The default password is configured in the compose file as `oracle` - - The `system`, `sys` and `pdbadmin` users all share this password + - The `system` and `pdbadmin` users share this password ## Instant Client diff --git a/packages/server/src/api/controllers/row/ExternalRequest.ts b/packages/server/src/api/controllers/row/ExternalRequest.ts index c1181dd6d5..c109a43afa 100644 --- a/packages/server/src/api/controllers/row/ExternalRequest.ts +++ b/packages/server/src/api/controllers/row/ExternalRequest.ts @@ -58,7 +58,7 @@ module External { ) { const primary = table.primary // if passed in array need to copy for shifting etc - let idCopy = cloneDeep(id) + let idCopy: undefined | string | any[] = cloneDeep(id) if (filters) { // need to map over the filters and make sure the _id field isn't present for (let filter of Object.values(filters)) { diff --git a/packages/server/src/api/routes/public/index.ts b/packages/server/src/api/routes/public/index.ts index 7e48e1a6a7..800eae6101 100644 --- a/packages/server/src/api/routes/public/index.ts +++ b/packages/server/src/api/routes/public/index.ts @@ -8,18 +8,54 @@ import authorized from "../../../middleware/authorized" import { paramResource, paramSubResource } from "../../../middleware/resourceId" import { CtxFn } from "./utils/Endpoint" import mapperMiddleware from "./middleware/mapper" +import env from "../../../environment" +// below imports don't have declaration files const Router = require("@koa/router") +const { RateLimit, Stores } = require("koa2-ratelimit") const { PermissionLevels, PermissionTypes, } = require("@budibase/backend-core/permissions") +const { getRedisOptions } = require("@budibase/backend-core/redis").utils const PREFIX = "/api/public/v1" +// allow a lot more requests when in test +const DEFAULT_API_REQ_LIMIT_PER_SEC = env.isTest() ? 100 : 10 + +function getApiLimitPerSecond(): number { + if (!env.API_REQ_LIMIT_PER_SEC) { + return DEFAULT_API_REQ_LIMIT_PER_SEC + } + return parseInt(env.API_REQ_LIMIT_PER_SEC) +} + +if (!env.isTest()) { + const REDIS_OPTS = getRedisOptions() + RateLimit.defaultOptions({ + store: new Stores.Redis({ + // @ts-ignore + socket: { + host: REDIS_OPTS.host, + port: REDIS_OPTS.port, + }, + password: REDIS_OPTS.opts.password, + database: 1, + }), + }) +} +// rate limiting, allows for 2 requests per second +const limiter = RateLimit.middleware({ + interval: { sec: 1 }, + // per ip, per interval + max: getApiLimitPerSecond(), +}) const publicRouter = new Router({ prefix: PREFIX, }) +publicRouter.use(limiter) + function addMiddleware( endpoints: any, middleware: CtxFn, diff --git a/packages/server/src/environment.js b/packages/server/src/environment.js index 7ed8b16b6f..312ecf313d 100644 --- a/packages/server/src/environment.js +++ b/packages/server/src/environment.js @@ -45,6 +45,7 @@ module.exports = { INTERNAL_API_KEY: process.env.INTERNAL_API_KEY, MULTI_TENANCY: process.env.MULTI_TENANCY, HTTP_MIGRATIONS: process.env.HTTP_MIGRATIONS, + API_REQ_LIMIT_PER_SEC: process.env.API_REQ_LIMIT_PER_SEC, // environment NODE_ENV: process.env.NODE_ENV, JEST_WORKER_ID: process.env.JEST_WORKER_ID, diff --git a/packages/server/src/integrations/base/datasourcePlus.ts b/packages/server/src/integrations/base/datasourcePlus.ts index 6ea748c22b..32edbc06a2 100644 --- a/packages/server/src/integrations/base/datasourcePlus.ts +++ b/packages/server/src/integrations/base/datasourcePlus.ts @@ -5,5 +5,8 @@ export interface DatasourcePlus extends IntegrationBase { tables: Record schemaErrors: Record + // if the datasource supports the use of bindings directly (to protect against SQL injection) + // this returns the format of the identifier + getBindingIdentifier(): string buildSchema(datasourceId: string, entities: Record): any } diff --git a/packages/server/src/integrations/googlesheets.ts b/packages/server/src/integrations/googlesheets.ts index 5f76e5b548..9f2f6bedf7 100644 --- a/packages/server/src/integrations/googlesheets.ts +++ b/packages/server/src/integrations/googlesheets.ts @@ -6,11 +6,10 @@ import { } from "../definitions/datasource" import { OAuth2Client } from "google-auth-library" import { DatasourcePlus } from "./base/datasourcePlus" -import { Row, Table, TableSchema } from "../definitions/common" +import { Table, TableSchema } from "../definitions/common" import { buildExternalTableId } from "./utils" import { DataSourceOperation, FieldTypes } from "../constants" import { GoogleSpreadsheet } from "google-spreadsheet" -import { table } from "console" module GoogleSheetsModule { const { getGlobalDB } = require("@budibase/backend-core/tenancy") @@ -112,6 +111,10 @@ module GoogleSheetsModule { this.client = new GoogleSpreadsheet(spreadsheetId) } + getBindingIdentifier() { + return "" + } + /** * Pull the spreadsheet ID out from a valid google sheets URL * @param spreadsheetId - the URL or standard spreadsheetId of the google sheet diff --git a/packages/server/src/integrations/microsoftSqlServer.ts b/packages/server/src/integrations/microsoftSqlServer.ts index 89fe47a38d..d6331ef25a 100644 --- a/packages/server/src/integrations/microsoftSqlServer.ts +++ b/packages/server/src/integrations/microsoftSqlServer.ts @@ -79,34 +79,9 @@ module MSSQLModule { }, } - async function internalQuery( - client: any, - query: SqlQuery, - operation: string | undefined = undefined - ) { - const request = client.request() - try { - if (Array.isArray(query.bindings)) { - let count = 0 - for (let binding of query.bindings) { - request.input(`p${count++}`, binding) - } - } - // this is a hack to get the inserted ID back, - // no way to do this with Knex nicely - const sql = - operation === Operation.CREATE - ? `${query.sql}; SELECT SCOPE_IDENTITY() AS id;` - : query.sql - return await request.query(sql) - } catch (err) { - // @ts-ignore - throw new Error(err) - } - } - class SqlServerIntegration extends Sql implements DatasourcePlus { private readonly config: MSSQLConfig + private index: number = 0 static pool: any public tables: Record = {} public schemaErrors: Record = {} @@ -121,6 +96,33 @@ module MSSQLModule { TABLES_SQL = "SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE='BASE TABLE'" + async internalQuery( + query: SqlQuery, + operation: string | undefined = undefined + ) { + const client = this.client + const request = client.request() + this.index = 0 + try { + if (Array.isArray(query.bindings)) { + let count = 0 + for (let binding of query.bindings) { + request.input(`p${count++}`, binding) + } + } + // this is a hack to get the inserted ID back, + // no way to do this with Knex nicely + const sql = + operation === Operation.CREATE + ? `${query.sql}; SELECT SCOPE_IDENTITY() AS id;` + : query.sql + return await request.query(sql) + } catch (err) { + // @ts-ignore + throw new Error(err) + } + } + getDefinitionSQL(tableName: string) { return `select * from INFORMATION_SCHEMA.COLUMNS @@ -165,6 +167,10 @@ module MSSQLModule { } } + getBindingIdentifier(): string { + return `(@p${this.index++})` + } + async connect() { try { this.client = await this.pool.connect() @@ -175,7 +181,7 @@ module MSSQLModule { } async runSQL(sql: string) { - return (await internalQuery(this.client, getSqlQuery(sql))).recordset + return (await this.internalQuery(getSqlQuery(sql))).recordset } /** @@ -238,33 +244,32 @@ module MSSQLModule { async read(query: SqlQuery | string) { await this.connect() - const response = await internalQuery(this.client, getSqlQuery(query)) + const response = await this.internalQuery(getSqlQuery(query)) return response.recordset } async create(query: SqlQuery | string) { await this.connect() - const response = await internalQuery(this.client, getSqlQuery(query)) + const response = await this.internalQuery(getSqlQuery(query)) return response.recordset || [{ created: true }] } async update(query: SqlQuery | string) { await this.connect() - const response = await internalQuery(this.client, getSqlQuery(query)) + const response = await this.internalQuery(getSqlQuery(query)) return response.recordset || [{ updated: true }] } async delete(query: SqlQuery | string) { await this.connect() - const response = await internalQuery(this.client, getSqlQuery(query)) + const response = await this.internalQuery(getSqlQuery(query)) return response.recordset || [{ deleted: true }] } async query(json: QueryJson) { await this.connect() const operation = this._operation(json) - const queryFn = (query: any, op: string) => - internalQuery(this.client, query, op) + const queryFn = (query: any, op: string) => this.internalQuery(query, op) const processFn = (result: any) => result.recordset ? result.recordset : [{ [operation]: true }] return this.queryWithReturning(json, queryFn, processFn) diff --git a/packages/server/src/integrations/mysql.ts b/packages/server/src/integrations/mysql.ts index 24a55a273d..42b53bc603 100644 --- a/packages/server/src/integrations/mysql.ts +++ b/packages/server/src/integrations/mysql.ts @@ -16,7 +16,7 @@ import { import { DatasourcePlus } from "./base/datasourcePlus" module MySQLModule { - const mysql = require("mysql2") + const mysql = require("mysql2/promise") const Sql = require("./base/sql") interface MySQLConfig { @@ -29,7 +29,7 @@ module MySQLModule { } const SCHEMA: Integration = { - docs: "https://github.com/mysqljs/mysql", + docs: "https://github.com/sidorares/node-mysql2", plus: true, friendlyName: "MySQL", description: @@ -80,36 +80,9 @@ module MySQLModule { }, } - function internalQuery( - client: any, - query: SqlQuery, - connect: boolean = true - ): Promise { - // Node MySQL is callback based, so we must wrap our call in a promise - return new Promise((resolve, reject) => { - if (connect) { - client.connect() - } - return client.query( - query.sql, - query.bindings || {}, - (error: any, results: object[]) => { - if (error) { - reject(error) - } else { - resolve(results) - } - if (connect) { - client.end() - } - } - ) - }) - } - class MySQLIntegration extends Sql implements DatasourcePlus { private config: MySQLConfig - private readonly client: any + private client: any public tables: Record = {} public schemaErrors: Record = {} @@ -119,93 +92,131 @@ module MySQLModule { if (config.ssl && Object.keys(config.ssl).length === 0) { delete config.ssl } - this.client = mysql.createConnection(config) + this.config = config + } + + getBindingIdentifier(): string { + return "?" + } + + async connect() { + this.client = await mysql.createConnection(this.config) + } + + async disconnect() { + await this.client.end() + } + + async internalQuery( + query: SqlQuery, + connect: boolean = true + ): Promise { + try { + if (connect) { + await this.connect() + } + // Node MySQL is callback based, so we must wrap our call in a promise + const response = await this.client.query( + query.sql, + query.bindings || [] + ) + return response[0] + } finally { + if (connect) { + await this.disconnect() + } + } } async buildSchema(datasourceId: string, entities: Record) { const tables: { [key: string]: Table } = {} const database = this.config.database - this.client.connect() + await this.connect() - // get the tables first - const tablesResp = await internalQuery( - this.client, - { sql: "SHOW TABLES;" }, - false - ) - const tableNames = tablesResp.map( - (obj: any) => - obj[`Tables_in_${database}`] || - obj[`Tables_in_${database.toLowerCase()}`] - ) - for (let tableName of tableNames) { - const primaryKeys = [] - const schema: TableSchema = {} - const descResp = await internalQuery( - this.client, - { sql: `DESCRIBE \`${tableName}\`;` }, + try { + // get the tables first + const tablesResp = await this.internalQuery( + { sql: "SHOW TABLES;" }, false ) - for (let column of descResp) { - const columnName = column.Field - if (column.Key === "PRI" && primaryKeys.indexOf(column.Key) === -1) { - primaryKeys.push(columnName) + const tableNames = tablesResp.map( + (obj: any) => + obj[`Tables_in_${database}`] || + obj[`Tables_in_${database.toLowerCase()}`] + ) + for (let tableName of tableNames) { + const primaryKeys = [] + const schema: TableSchema = {} + const descResp = await this.internalQuery( + { sql: `DESCRIBE \`${tableName}\`;` }, + false + ) + for (let column of descResp) { + const columnName = column.Field + if ( + column.Key === "PRI" && + primaryKeys.indexOf(column.Key) === -1 + ) { + primaryKeys.push(columnName) + } + const constraints = { + presence: column.Null !== "YES", + } + const isAuto: boolean = + typeof column.Extra === "string" && + (column.Extra === "auto_increment" || + column.Extra.toLowerCase().includes("generated")) + schema[columnName] = { + name: columnName, + autocolumn: isAuto, + type: convertSqlType(column.Type), + constraints, + } } - const constraints = { - presence: column.Null !== "YES", - } - const isAuto: boolean = - typeof column.Extra === "string" && - (column.Extra === "auto_increment" || - column.Extra.toLowerCase().includes("generated")) - schema[columnName] = { - name: columnName, - autocolumn: isAuto, - type: convertSqlType(column.Type), - constraints, - } - } - if (!tables[tableName]) { - tables[tableName] = { - _id: buildExternalTableId(datasourceId, tableName), - primary: primaryKeys, - name: tableName, - schema, + if (!tables[tableName]) { + tables[tableName] = { + _id: buildExternalTableId(datasourceId, tableName), + primary: primaryKeys, + name: tableName, + schema, + } } } + } finally { + await this.disconnect() } - - this.client.end() const final = finaliseExternalTables(tables, entities) this.tables = final.tables this.schemaErrors = final.errors } async create(query: SqlQuery | string) { - const results = await internalQuery(this.client, getSqlQuery(query)) + const results = await this.internalQuery(getSqlQuery(query)) return results.length ? results : [{ created: true }] } async read(query: SqlQuery | string) { - return internalQuery(this.client, getSqlQuery(query)) + return this.internalQuery(getSqlQuery(query)) } async update(query: SqlQuery | string) { - const results = await internalQuery(this.client, getSqlQuery(query)) + const results = await this.internalQuery(getSqlQuery(query)) return results.length ? results : [{ updated: true }] } async delete(query: SqlQuery | string) { - const results = await internalQuery(this.client, getSqlQuery(query)) + const results = await this.internalQuery(getSqlQuery(query)) return results.length ? results : [{ deleted: true }] } async query(json: QueryJson) { - this.client.connect() - const queryFn = (query: any) => internalQuery(this.client, query, false) - const output = await this.queryWithReturning(json, queryFn) - this.client.end() - return output + await this.connect() + try { + const queryFn = (query: any) => this.internalQuery(query, false) + return await this.queryWithReturning(json, queryFn) + } finally { + await this.disconnect() + } } } diff --git a/packages/server/src/integrations/oracle.ts b/packages/server/src/integrations/oracle.ts index f602a97591..bb4ef70403 100644 --- a/packages/server/src/integrations/oracle.ts +++ b/packages/server/src/integrations/oracle.ts @@ -1,24 +1,24 @@ import { - Integration, DatasourceFieldTypes, + Integration, + Operation, + QueryJson, QueryTypes, SqlQuery, - QueryJson, - Operation, } from "../definitions/datasource" import { - finaliseExternalTables, - getSqlQuery, buildExternalTableId, convertSqlType, + finaliseExternalTables, + getSqlQuery, SqlClients, } from "./utils" import oracledb, { - ExecuteOptions, - Result, + BindParameters, Connection, ConnectionAttributes, - BindParameters, + ExecuteOptions, + Result, } from "oracledb" import Sql from "./base/sql" import { Table } from "../definitions/common" @@ -137,6 +137,7 @@ module OracleModule { class OracleIntegration extends Sql implements DatasourcePlus { private readonly config: OracleConfig + private index: number = 1 public tables: Record = {} public schemaErrors: Record = {} @@ -174,6 +175,10 @@ module OracleModule { this.config = config } + getBindingIdentifier(): string { + return `:${this.index++}` + } + /** * Map the flat tabular columns and constraints data into a nested object */ @@ -233,20 +238,14 @@ module OracleModule { return oracleTables } - private isSupportedColumn(column: OracleColumn) { - if (UNSUPPORTED_TYPES.includes(column.type)) { - return false - } - - return true + private static isSupportedColumn(column: OracleColumn) { + return !UNSUPPORTED_TYPES.includes(column.type) } - private isAutoColumn(column: OracleColumn) { - if (column.default && column.default.toLowerCase().includes("nextval")) { - return true - } - - return false + private static isAutoColumn(column: OracleColumn) { + return !!( + column.default && column.default.toLowerCase().includes("nextval") + ) } /** @@ -254,7 +253,7 @@ module OracleModule { * This matches the default behaviour for generating DDL used in knex. */ private isBooleanType(column: OracleColumn): boolean { - if ( + return ( column.type.toLowerCase() === "number" && Object.values(column.constraints).filter(c => { if ( @@ -273,11 +272,7 @@ module OracleModule { } return false }).length > 0 - ) { - return true - } - - return false + ) } private internalConvertType(column: OracleColumn): string { @@ -317,7 +312,9 @@ module OracleModule { // iterate each column on the table Object.values(oracleTable.columns) // remove columns that we can't read / save - .filter(oracleColumn => this.isSupportedColumn(oracleColumn)) + .filter(oracleColumn => + OracleIntegration.isSupportedColumn(oracleColumn) + ) // match the order of the columns in the db .sort((c1, c2) => c1.id - c2.id) .forEach(oracleColumn => { @@ -325,7 +322,7 @@ module OracleModule { let fieldSchema = table.schema[columnName] if (!fieldSchema) { fieldSchema = { - autocolumn: this.isAutoColumn(oracleColumn), + autocolumn: OracleIntegration.isAutoColumn(oracleColumn), name: columnName, type: this.internalConvertType(oracleColumn), } @@ -351,18 +348,13 @@ module OracleModule { private async internalQuery(query: SqlQuery): Promise> { let connection try { + this.index = 1 connection = await this.getConnection() const options: ExecuteOptions = { autoCommit: true } const bindings: BindParameters = query.bindings || [] - const result: Result = await connection.execute( - query.sql, - bindings, - options - ) - - return result + return await connection.execute(query.sql, bindings, options) } finally { if (connection) { try { diff --git a/packages/server/src/integrations/postgres.ts b/packages/server/src/integrations/postgres.ts index b2e48ad540..e86cd89c03 100644 --- a/packages/server/src/integrations/postgres.ts +++ b/packages/server/src/integrations/postgres.ts @@ -103,30 +103,11 @@ module PostgresModule { }, } - async function internalQuery(client: any, query: SqlQuery) { - // need to handle a specific issue with json data types in postgres, - // new lines inside the JSON data will break it - if (query && query.sql) { - const matches = query.sql.match(JSON_REGEX) - if (matches && matches.length > 0) { - for (let match of matches) { - const escaped = escapeDangerousCharacters(match) - query.sql = query.sql.replace(match, escaped) - } - } - } - try { - return await client.query(query.sql, query.bindings || []) - } catch (err) { - // @ts-ignore - throw new Error(err) - } - } - class PostgresIntegration extends Sql implements DatasourcePlus { static pool: any private readonly client: any private readonly config: PostgresConfig + private index: number = 1 public tables: Record = {} public schemaErrors: Record = {} @@ -163,6 +144,32 @@ module PostgresModule { this.setSchema() } + getBindingIdentifier(): string { + return `$${this.index++}` + } + + async internalQuery(query: SqlQuery) { + const client = this.client + this.index = 1 + // need to handle a specific issue with json data types in postgres, + // new lines inside the JSON data will break it + if (query && query.sql) { + const matches = query.sql.match(JSON_REGEX) + if (matches && matches.length > 0) { + for (let match of matches) { + const escaped = escapeDangerousCharacters(match) + query.sql = query.sql.replace(match, escaped) + } + } + } + try { + return await client.query(query.sql, query.bindings || []) + } catch (err) { + // @ts-ignore + throw new Error(err) + } + } + setSchema() { if (!this.config.schema) { this.config.schema = "public" @@ -241,22 +248,22 @@ module PostgresModule { } async create(query: SqlQuery | string) { - const response = await internalQuery(this.client, getSqlQuery(query)) + const response = await this.internalQuery(getSqlQuery(query)) return response.rows.length ? response.rows : [{ created: true }] } async read(query: SqlQuery | string) { - const response = await internalQuery(this.client, getSqlQuery(query)) + const response = await this.internalQuery(getSqlQuery(query)) return response.rows } async update(query: SqlQuery | string) { - const response = await internalQuery(this.client, getSqlQuery(query)) + const response = await this.internalQuery(getSqlQuery(query)) return response.rows.length ? response.rows : [{ updated: true }] } async delete(query: SqlQuery | string) { - const response = await internalQuery(this.client, getSqlQuery(query)) + const response = await this.internalQuery(getSqlQuery(query)) return response.rows.length ? response.rows : [{ deleted: true }] } @@ -266,11 +273,11 @@ module PostgresModule { if (Array.isArray(input)) { const responses = [] for (let query of input) { - responses.push(await internalQuery(this.client, query)) + responses.push(await this.internalQuery(query)) } return responses } else { - const response = await internalQuery(this.client, input) + const response = await this.internalQuery(input) return response.rows.length ? response.rows : [{ [operation]: true }] } } diff --git a/packages/server/src/integrations/tests/mysql.spec.js b/packages/server/src/integrations/tests/mysql.spec.js index 47ca3688f0..8304771d5d 100644 --- a/packages/server/src/integrations/tests/mysql.spec.js +++ b/packages/server/src/integrations/tests/mysql.spec.js @@ -19,7 +19,7 @@ describe("MySQL Integration", () => { await config.integration.create({ sql }) - expect(config.integration.client.query).toHaveBeenCalledWith(sql, {}, expect.any(Function)) + expect(config.integration.client.query).toHaveBeenCalledWith(sql, []) }) it("calls the read method with the correct params", async () => { @@ -27,7 +27,7 @@ describe("MySQL Integration", () => { await config.integration.read({ sql }) - expect(config.integration.client.query).toHaveBeenCalledWith(sql, {}, expect.any(Function)) + expect(config.integration.client.query).toHaveBeenCalledWith(sql, []) }) it("calls the update method with the correct params", async () => { @@ -35,7 +35,7 @@ describe("MySQL Integration", () => { await config.integration.update({ sql }) - expect(config.integration.client.query).toHaveBeenCalledWith(sql, {}, expect.any(Function)) + expect(config.integration.client.query).toHaveBeenCalledWith(sql, []) }) it("calls the delete method with the correct params", async () => { @@ -43,7 +43,7 @@ describe("MySQL Integration", () => { await config.integration.delete({ sql }) - expect(config.integration.client.query).toHaveBeenCalledWith(sql, {}, expect.any(Function)) + expect(config.integration.client.query).toHaveBeenCalledWith(sql, []) }) describe("no rows returned", () => { diff --git a/packages/server/src/integrations/utils.ts b/packages/server/src/integrations/utils.ts index 1341f5abca..26e35f300f 100644 --- a/packages/server/src/integrations/utils.ts +++ b/packages/server/src/integrations/utils.ts @@ -40,7 +40,7 @@ const SQL_TYPE_MAP = { export enum SqlClients { MS_SQL = "mssql", POSTGRES = "pg", - MY_SQL = "mysql", + MY_SQL = "mysql2", ORACLE = "oracledb", } diff --git a/packages/server/src/threads/query.js b/packages/server/src/threads/query.js index 5b1a30b57d..36bc3d7f36 100644 --- a/packages/server/src/threads/query.js +++ b/packages/server/src/threads/query.js @@ -2,8 +2,12 @@ const threadUtils = require("./utils") threadUtils.threadSetup() const ScriptRunner = require("../utilities/scriptRunner") const { integrations } = require("../integrations") -const { processStringSync } = require("@budibase/string-templates") +const { + processStringSync, + findHBSBlocks, +} = require("@budibase/string-templates") const { doInAppContext, getAppDB } = require("@budibase/backend-core/context") +const { isSQL } = require("../integrations/utils") class QueryRunner { constructor(input, flags = { noRecursiveQuery: false }) { @@ -23,23 +27,47 @@ class QueryRunner { this.hasRerun = false } + interpolateSQL(fields, parameters, integration) { + let sql = fields.sql + if (!sql) { + return fields + } + const bindings = findHBSBlocks(sql) + let variables = [] + for (let binding of bindings) { + let variable = integration.getBindingIdentifier() + variables.push(binding) + sql = sql.replace(binding, variable) + } + // replicate the knex structure + fields.sql = sql + fields.bindings = this.enrichQueryFields(variables, parameters) + return fields + } + async execute() { let { datasource, fields, queryVerb, transformer } = this - // pre-query, make sure datasource variables are added to parameters - const parameters = await this.addDatasourceVariables() - let query = this.enrichQueryFields(fields, parameters) - - // Add pagination values for REST queries - if (this.pagination) { - query.paginationValues = this.pagination - } - const Integration = integrations[datasource.source] if (!Integration) { throw "Integration type does not exist." } const integration = new Integration(datasource.config) + // pre-query, make sure datasource variables are added to parameters + const parameters = await this.addDatasourceVariables() + let query + // handle SQL injections by interpolating the variables + if (isSQL(datasource)) { + query = this.interpolateSQL(fields, parameters, integration) + } else { + query = this.enrichQueryFields(fields, parameters) + } + + // Add pagination values for REST queries + if (this.pagination) { + query.paginationValues = this.pagination + } + let output = threadUtils.formatResponse(await integration[queryVerb](query)) let rows = output, info = undefined, @@ -179,7 +207,7 @@ class QueryRunner { } enrichQueryFields(fields, parameters = {}) { - const enrichedQuery = {} + const enrichedQuery = Array.isArray(fields) ? [] : {} // enrich the fields with dynamic parameters for (let key of Object.keys(fields)) { diff --git a/packages/server/yarn.lock b/packages/server/yarn.lock index b91c23776a..95c1e6736a 100644 --- a/packages/server/yarn.lock +++ b/packages/server/yarn.lock @@ -995,10 +995,10 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@budibase/backend-core@^1.0.79-alpha.5": - version "1.0.79-alpha.5" - resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-1.0.79-alpha.5.tgz#dac73ccfcd2e6e63415cde6d76e4bf09043dc6b6" - integrity sha512-m7/z55fp+EYVYEAyuQ2K//AcrfgzLBcR4EVjP+rrmbIhGFbLV2ASl5IBg9bcAYp0z2m816skJrY2asx9raWhgw== +"@budibase/backend-core@^1.0.79-alpha.9": + version "1.0.79-alpha.9" + resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-1.0.79-alpha.9.tgz#5d770d65f0375d93a382d8a32d0427e935fb2152" + integrity sha512-EV9hreLMvapZqZ/P99u4Ke2hO1w1GamGBHFri5MzLA9Njc5YRJzoDoy/Awg7k1piu3OIW2Sjk0b5VA+v3iaMnA== dependencies: "@techpass/passport-openidconnect" "^0.3.0" aws-sdk "^2.901.0" @@ -1068,7 +1068,7 @@ svelte-flatpickr "^3.2.3" svelte-portal "^1.0.0" -"@budibase/bbui@^1.0.79-alpha.5": +"@budibase/bbui@^1.0.79-alpha.9": version "1.58.13" resolved "https://registry.yarnpkg.com/@budibase/bbui/-/bbui-1.58.13.tgz#59df9c73def2d81c75dcbd2266c52c19db88dbd7" integrity sha512-Zk6CKXdBfKsTVzA1Xs5++shdSSZLfphVpZuKVbjfzkgtuhyH7ruucexuSHEpFsxjW5rEKgKIBoRFzCK5vPvN0w== @@ -1080,14 +1080,14 @@ svelte-portal "^1.0.0" turndown "^7.0.0" -"@budibase/client@^1.0.79-alpha.5": - version "1.0.79-alpha.5" - resolved "https://registry.yarnpkg.com/@budibase/client/-/client-1.0.79-alpha.5.tgz#d729858b10e6cd2a506fb63364a0e7ab3149780e" - integrity sha512-OrBErU97YL67GggsLmcD46AUElSgtyFjZdCXi++3s4zaZYZxT4Ix2iFMrnslcpF87bv8xyiSt3vsyCPGKCU5wQ== +"@budibase/client@^1.0.79-alpha.9": + version "1.0.79-alpha.9" + resolved "https://registry.yarnpkg.com/@budibase/client/-/client-1.0.79-alpha.9.tgz#526efb411c85cc871b0aa2717a6d1dce1c6496ef" + integrity sha512-x9F7s02jcgU1QlpUaEDj1kvMJqRJPzw+wcZfFyVPkRjZtZo9PnzDXQ+kZ6bqiKfyf/qNJ1SM1jzEAl1uzUj7vA== dependencies: - "@budibase/bbui" "^1.0.79-alpha.5" - "@budibase/frontend-core" "^1.0.79-alpha.5" - "@budibase/string-templates" "^1.0.79-alpha.5" + "@budibase/bbui" "^1.0.79-alpha.9" + "@budibase/frontend-core" "^1.0.79-alpha.9" + "@budibase/string-templates" "^1.0.79-alpha.9" "@spectrum-css/button" "^3.0.3" "@spectrum-css/card" "^3.0.3" "@spectrum-css/divider" "^1.0.3" @@ -1106,12 +1106,12 @@ svelte-flatpickr "^3.1.0" svelte-spa-router "^3.0.5" -"@budibase/frontend-core@^1.0.79-alpha.5": - version "1.0.79-alpha.5" - resolved "https://registry.yarnpkg.com/@budibase/frontend-core/-/frontend-core-1.0.79-alpha.5.tgz#7da5faf83d6cc5a59d8e038c2e9333e27bff35d5" - integrity sha512-5xti0MdKRvNKwYUE5cp4rH8IwLPmuRz39ajck947ut2OWzXV9bt7SXzoKPSSzEGdCBA2DgzJpK3gQWYlqXiJiQ== +"@budibase/frontend-core@^1.0.79-alpha.9": + version "1.0.79-alpha.9" + resolved "https://registry.yarnpkg.com/@budibase/frontend-core/-/frontend-core-1.0.79-alpha.9.tgz#3441f03370744204d3614a106e8544ceb70b2abd" + integrity sha512-bZrV2ifcGGK/G1adAGqRHJ9OGGnGMzany9bonzInrF1YoqfT9TE9sGpfDdm7I8jfvSsidXUEY0/KJBLPMo4+4g== dependencies: - "@budibase/bbui" "^1.0.79-alpha.5" + "@budibase/bbui" "^1.0.79-alpha.9" lodash "^4.17.21" svelte "^3.46.2" @@ -1158,10 +1158,10 @@ svelte-apexcharts "^1.0.2" svelte-flatpickr "^3.1.0" -"@budibase/string-templates@^1.0.79-alpha.5": - version "1.0.79-alpha.5" - resolved "https://registry.yarnpkg.com/@budibase/string-templates/-/string-templates-1.0.79-alpha.5.tgz#063f5beca7d3b4a9757df77dcf1bd8a442d7522e" - integrity sha512-Rifn1h1Pn53KYCFX6GHmMq+fD4IEnfRXEWrf4RD7cy4TVCYqCIcI84tnzUwibkyuCbpDw4zh0RR0m4nemf7heg== +"@budibase/string-templates@^1.0.79-alpha.9": + version "1.0.79-alpha.9" + resolved "https://registry.yarnpkg.com/@budibase/string-templates/-/string-templates-1.0.79-alpha.9.tgz#5b1b9401f97ca691b4a74c10901bb878a14067b6" + integrity sha512-BlqiCLIobVDoXV4UBeyZ5UaTF8INihvmR+ihr0862TOhdcthSRkb2HOfoB3aAm5XYhe7NpLnJepDRG+1sefDgA== dependencies: "@budibase/handlebars-helpers" "^0.11.8" dayjs "^1.10.4" @@ -1885,6 +1885,41 @@ path-to-regexp "^1.1.1" urijs "^1.19.0" +"@node-redis/bloom@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@node-redis/bloom/-/bloom-1.0.1.tgz#144474a0b7dc4a4b91badea2cfa9538ce0a1854e" + integrity sha512-mXEBvEIgF4tUzdIN89LiYsbi6//EdpFA7L8M+DHCvePXg+bfHWi+ct5VI6nHUFQE5+ohm/9wmgihCH3HSkeKsw== + +"@node-redis/client@1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@node-redis/client/-/client-1.0.4.tgz#fe185750df3bcc07524f63fe8dbc8d14d22d6cbb" + integrity sha512-IM/NRAqg7MvNC3bIRQipXGrEarunrdgvrbAzsd3ty93LSHi/M+ybQulOERQi8a3M+P5BL8HenwXjiIoKm6ml2g== + dependencies: + cluster-key-slot "1.1.0" + generic-pool "3.8.2" + redis-parser "3.0.0" + yallist "4.0.0" + +"@node-redis/graph@1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@node-redis/graph/-/graph-1.0.0.tgz#baf8eaac4a400f86ea04d65ec3d65715fd7951ab" + integrity sha512-mRSo8jEGC0cf+Rm7q8mWMKKKqkn6EAnA9IA2S3JvUv/gaWW/73vil7GLNwion2ihTptAm05I9LkepzfIXUKX5g== + +"@node-redis/json@1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@node-redis/json/-/json-1.0.2.tgz#8ad2d0f026698dc1a4238cc3d1eb099a3bee5ab8" + integrity sha512-qVRgn8WfG46QQ08CghSbY4VhHFgaTY71WjpwRBGEuqGPfWwfRcIf3OqSpR7Q/45X+v3xd8mvYjywqh0wqJ8T+g== + +"@node-redis/search@1.0.3": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@node-redis/search/-/search-1.0.3.tgz#7c3d026bf994caf82019fd0c3924cfc09f041a29" + integrity sha512-rsrzkGWI84di/uYtEctS/4qLusWt0DESx/psjfB0TFpORDhe7JfC0h8ary+eHulTksumor244bXLRSqQXbFJmw== + +"@node-redis/time-series@1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@node-redis/time-series/-/time-series-1.0.2.tgz#5dd3638374edd85ebe0aa6b0e87addc88fb9df69" + integrity sha512-HGQ8YooJ8Mx7l28tD7XjtB3ImLEjlUxG1wC1PAjxu6hPJqjPshUZxAICzDqDjtIbhDTf48WXXUcx8TQJB1XTKA== + "@nodelib/fs.scandir@2.1.5": version "2.1.5" resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" @@ -2351,6 +2386,11 @@ dependencies: "@babel/types" "^7.3.0" +"@types/bluebird@*": + version "3.5.36" + resolved "https://registry.yarnpkg.com/@types/bluebird/-/bluebird-3.5.36.tgz#00d9301d4dc35c2f6465a8aec634bb533674c652" + integrity sha512-HBNx4lhkxN7bx6P0++W8E289foSu8kO8GCk2unhuVggO+cE7rh9DhZUyPhUxNRG9m+5B5BTKxZQ5ZP92x/mx9Q== + "@types/body-parser@*": version "1.19.2" resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.2.tgz#aea2059e28b7658639081347ac4fab3de166e6f0" @@ -2383,6 +2423,13 @@ resolved "https://registry.yarnpkg.com/@types/content-disposition/-/content-disposition-0.5.4.tgz#de48cf01c79c9f1560bcfd8ae43217ab028657f8" integrity sha512-0mPF08jn9zYI0n0Q/Pnz7C4kThdSt+6LD4amsrYDDpgBfrVWa3TcCOxKX1zkGgYniGagRv8heN2cbh+CAn+uuQ== +"@types/continuation-local-storage@*": + version "3.2.4" + resolved "https://registry.yarnpkg.com/@types/continuation-local-storage/-/continuation-local-storage-3.2.4.tgz#655c8ffd9327aa60fb8ae773a5f2efbc973a7cbb" + integrity sha512-OT32vCVMymU1JMPKDeY0lX3cduAr0Pm/VwIbxygMeDS4lRcv57qYXn9bMwBRcRnEpXKBb/r4xYaZCARTZllP0A== + dependencies: + "@types/node" "*" + "@types/cookiejar@*": version "2.1.2" resolved "https://registry.yarnpkg.com/@types/cookiejar/-/cookiejar-2.1.2.tgz#66ad9331f63fe8a3d3d9d8c6e3906dd10f6446e8" @@ -2538,6 +2585,16 @@ dependencies: "@types/koa" "*" +"@types/koa2-ratelimit@^0.9.2": + version "0.9.2" + resolved "https://registry.yarnpkg.com/@types/koa2-ratelimit/-/koa2-ratelimit-0.9.2.tgz#5853e2db9d61ea596ffa8c0ef5ec545c5f5351f0" + integrity sha512-wHBO8fCFUX86lc41GNj/WR1Ao6CW47bPWJO3b14LLSc8j927ev8F/ELj7FKXlyUPWC/CFKZTW8PpKLufjK8Eqg== + dependencies: + "@types/koa" "*" + "@types/mongoose" "5.10.5" + "@types/redis" "^2.8.0" + "@types/sequelize" "*" + "@types/koa@*", "@types/koa@^2.13.3": version "2.13.4" resolved "https://registry.yarnpkg.com/@types/koa/-/koa-2.13.4.tgz#10620b3f24a8027ef5cbae88b393d1b31205726b" @@ -2552,11 +2609,38 @@ "@types/koa-compose" "*" "@types/node" "*" +"@types/lodash@*": + version "4.14.179" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.179.tgz#490ec3288088c91295780237d2497a3aa9dfb5c5" + integrity sha512-uwc1x90yCKqGcIOAT6DwOSuxnrAbpkdPsUOZtwrXb4D/6wZs+6qG7QnIawDuZWg0sWpxl+ltIKCaLoMlna678w== + "@types/mime@^1": version "1.3.2" resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.2.tgz#93e25bf9ee75fe0fd80b594bc4feb0e862111b5a" integrity sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw== +"@types/mongodb@*", "@types/mongodb@^4.0.7": + version "4.0.7" + resolved "https://registry.yarnpkg.com/@types/mongodb/-/mongodb-4.0.7.tgz#ebaa80c53b684ea52ccfe7721c0f5c9ef7b4f511" + integrity sha512-lPUYPpzA43baXqnd36cZ9xxorprybxXDzteVKCPAdp14ppHtFJHnXYvNpmBvtMUTb5fKXVv6sVbzo1LHkWhJlw== + dependencies: + mongodb "*" + +"@types/mongoose@5.10.5": + version "5.10.5" + resolved "https://registry.yarnpkg.com/@types/mongoose/-/mongoose-5.10.5.tgz#0f4fb0440e8cf0213caec1e5c7b163dbd9847c56" + integrity sha512-37QMIA954T3n+HSksSNLlxZsqF8fMJu5S4dyPBod6gRxGtsXlQ9jUtL8BE8Seimv99u79eLXI3bggoCnSQ/fxQ== + dependencies: + "@types/mongodb" "*" + "@types/node" "*" + +"@types/mongoose@^5.11.97": + version "5.11.97" + resolved "https://registry.yarnpkg.com/@types/mongoose/-/mongoose-5.11.97.tgz#80b0357f3de6807eb597262f52e49c3e13ee14d8" + integrity sha512-cqwOVYT3qXyLiGw7ueU2kX9noE8DPGRY6z8eUxudhXY8NZ7DMKYAxyZkLSevGfhCX3dO/AoX5/SO9lAzfjon0Q== + dependencies: + mongoose "*" + "@types/node@*", "@types/node@>=13.13.4": version "16.11.7" resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.7.tgz#36820945061326978c42a01e56b61cd223dfdc42" @@ -2608,6 +2692,20 @@ "@types/node" "*" safe-buffer "*" +"@types/redis@^2.8.0": + version "2.8.32" + resolved "https://registry.yarnpkg.com/@types/redis/-/redis-2.8.32.tgz#1d3430219afbee10f8cfa389dad2571a05ecfb11" + integrity sha512-7jkMKxcGq9p242exlbsVzuJb57KqHRhNl4dHoQu2Y5v9bCAbtIXXH0R3HleSQW4CTOqpHIYUW3t6tpUj4BVQ+w== + dependencies: + "@types/node" "*" + +"@types/redis@^4.0.11": + version "4.0.11" + resolved "https://registry.yarnpkg.com/@types/redis/-/redis-4.0.11.tgz#0bb4c11ac9900a21ad40d2a6768ec6aaf651c0e1" + integrity sha512-bI+gth8La8Wg/QCR1+V1fhrL9+LZUSWfcqpOj2Kc80ZQ4ffbdL173vQd5wovmoV9i071FU9oP2g6etLuEwb6Rg== + dependencies: + redis "*" + "@types/request@^2.48.7": version "2.48.8" resolved "https://registry.yarnpkg.com/@types/request/-/request-2.48.8.tgz#0b90fde3b655ab50976cb8c5ac00faca22f5a82c" @@ -2618,6 +2716,16 @@ "@types/tough-cookie" "*" form-data "^2.5.0" +"@types/sequelize@*": + version "4.28.11" + resolved "https://registry.yarnpkg.com/@types/sequelize/-/sequelize-4.28.11.tgz#8b0c530bac4e6d73a0416a94db0de820cc4d47c3" + integrity sha512-2zeMcB5ZI+u1UwxM4sa3gLu8eSp0Gk+emTKPWXuNk3ePFo4EUYLgmIhGV6b+kYoshXpZHG3nJVMK00tuh5vEQA== + dependencies: + "@types/bluebird" "*" + "@types/continuation-local-storage" "*" + "@types/lodash" "*" + "@types/validator" "*" + "@types/serve-static@*": version "1.13.10" resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.10.tgz#f5e0ce8797d2d7cc5ebeda48a52c96c4fa47a8d9" @@ -2649,6 +2757,24 @@ resolved "https://registry.yarnpkg.com/@types/tough-cookie/-/tough-cookie-4.0.1.tgz#8f80dd965ad81f3e1bc26d6f5c727e132721ff40" integrity sha512-Y0K95ThC3esLEYD6ZuqNek29lNX2EM1qxV8y2FTLUB0ff5wWrk7az+mLrnNFUnaXcgKye22+sFBRXOgpPILZNg== +"@types/validator@*": + version "13.7.1" + resolved "https://registry.yarnpkg.com/@types/validator/-/validator-13.7.1.tgz#cdab1b4779f6b1718a08de89d92d2603b71950cb" + integrity sha512-I6OUIZ5cYRk5lp14xSOAiXjWrfVoMZVjDuevBYgQDYzZIjsf2CAISpEcXOkFAtpAHbmWIDLcZObejqny/9xq5Q== + +"@types/webidl-conversions@*": + version "6.1.1" + resolved "https://registry.yarnpkg.com/@types/webidl-conversions/-/webidl-conversions-6.1.1.tgz#e33bc8ea812a01f63f90481c666334844b12a09e" + integrity sha512-XAahCdThVuCFDQLT7R7Pk/vqeObFNL3YqRyFZg+AqAP/W1/w3xHaIxuW7WszQqTbIBOPRcItYJIou3i/mppu3Q== + +"@types/whatwg-url@^8.2.1": + version "8.2.1" + resolved "https://registry.yarnpkg.com/@types/whatwg-url/-/whatwg-url-8.2.1.tgz#f1aac222dab7c59e011663a0cb0a3117b2ef05d4" + integrity sha512-2YubE1sjj5ifxievI5Ge1sckb9k/Er66HyR2c+3+I6VDUUg1TLPdYYTEbQ+DjRkS4nTxMJhgWfSfMRD2sl2EYQ== + dependencies: + "@types/node" "*" + "@types/webidl-conversions" "*" + "@types/yargs-parser@*": version "20.2.1" resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-20.2.1.tgz#3b9ce2489919d9e4fea439b76916abc34b2df129" @@ -3774,6 +3900,13 @@ bson@^1.1.4: resolved "https://registry.yarnpkg.com/bson/-/bson-1.1.6.tgz#fb819be9a60cd677e0853aee4ca712a785d6618a" integrity sha512-EvVNVeGo4tHxwi8L6bPj3y3itEvStdwvvlojVxxbyYfoaxJ6keLgrTuKdyfEAszFK+H3olzBuafE0yoh0D1gdg== +bson@^4.2.2, bson@^4.6.1: + version "4.6.1" + resolved "https://registry.yarnpkg.com/bson/-/bson-4.6.1.tgz#2b5da517539bb0f7f3ffb54ac70a384ca899641c" + integrity sha512-I1LQ7Hz5zgwR4QquilLNZwbhPw0Apx7i7X9kGMBTsqPdml/03Q9NBtD9nt/19ahjlphktQImrnderxqpzeVDjw== + dependencies: + buffer "^5.6.0" + buffer-alloc-unsafe@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0" @@ -4124,7 +4257,7 @@ cls-hooked@^4.2.2: emitter-listener "^1.0.1" semver "^5.4.1" -cluster-key-slot@^1.1.0: +cluster-key-slot@1.1.0, cluster-key-slot@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz#30474b2a981fb12172695833052bc0d01336d10d" integrity sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw== @@ -4564,6 +4697,13 @@ debug@4, debug@4.3.2, debug@^4, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@ dependencies: ms "2.1.2" +debug@4.x: + version "4.3.3" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664" + integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q== + dependencies: + ms "2.1.2" + debug@^2.2.0, debug@^2.3.3: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" @@ -6103,6 +6243,11 @@ generate-function@^2.3.1: dependencies: is-property "^1.0.2" +generic-pool@3.8.2: + version "3.8.2" + resolved "https://registry.yarnpkg.com/generic-pool/-/generic-pool-3.8.2.tgz#aab4f280adb522fdfbdc5e5b64d718d3683f04e9" + integrity sha512-nGToKy6p3PAbYQ7p1UlWl6vSPwfwU6TMSWK7TTu+WUY4ZjyZQGniGGt2oNVvyNSpyZYSB43zMXVLcBm08MTMkg== + gensync@^1.0.0-beta.2: version "1.0.0-beta.2" resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" @@ -6927,6 +7072,11 @@ ip-regex@^2.1.0: resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9" integrity sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk= +ip@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" + integrity sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo= + is-accessor-descriptor@^0.1.6: version "0.1.6" resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" @@ -8501,6 +8651,11 @@ jws@^4.0.0: jwa "^2.0.0" safe-buffer "^5.0.1" +kareem@2.3.4: + version "2.3.4" + resolved "https://registry.yarnpkg.com/kareem/-/kareem-2.3.4.tgz#b38c436fb4758775d919b2828b4009db59b52694" + integrity sha512-Vcrt8lcpVl0s8ePx634BxwRqmFo+5DcOhlmNadehxreMTIQi/9hOL/B3hZQQbK5DgMS7Lem3xABXV7/S3jy+7g== + keygrip@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/keygrip/-/keygrip-1.0.3.tgz#399d709f0aed2bab0a059e0cdd3a5023a053e1dc" @@ -8707,6 +8862,11 @@ koa-views@^7.0.1: pretty "^2.0.0" resolve-path "^1.4.0" +koa2-ratelimit@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/koa2-ratelimit/-/koa2-ratelimit-1.1.0.tgz#5ab432fdda7b2d63a4fb1b9a0d994c1264396aff" + integrity sha512-AumRCI8YO9TMF9trVP6j68K5qzi21ajZUOCb5VuPWq9pZw+FHXam275S5P1IDAlZjs1cDFBOAAkhwTdTbVCcsg== + koa@2.7.0: version "2.7.0" resolved "https://registry.yarnpkg.com/koa/-/koa-2.7.0.tgz#7e00843506942b9d82c6cc33749f657c6e5e7adf" @@ -9485,6 +9645,26 @@ moment-timezone@^0.5.31: resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.1.tgz#b2be769fa31940be9eeea6469c075e35006fa3d3" integrity sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ== +mongodb-connection-string-url@^2.4.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/mongodb-connection-string-url/-/mongodb-connection-string-url-2.5.2.tgz#f075c8d529e8d3916386018b8a396aed4f16e5ed" + integrity sha512-tWDyIG8cQlI5k3skB6ywaEA5F9f5OntrKKsT/Lteub2zgwSUlhqEN2inGgBTm8bpYJf8QYBdA/5naz65XDpczA== + dependencies: + "@types/whatwg-url" "^8.2.1" + whatwg-url "^11.0.0" + +mongodb@*: + version "4.4.0" + resolved "https://registry.yarnpkg.com/mongodb/-/mongodb-4.4.0.tgz#3b14b9701067713d5c9afb6d6e4a86ca7b969824" + integrity sha512-1hPhutJj6yxxu0ymwsO0uEimTo+QTh3oQP6YHxmLneBFBOGydYFdnmDDuLiGWimAlMdRN9WuDXY+JGp47aeOwA== + dependencies: + bson "^4.6.1" + denque "^2.0.1" + mongodb-connection-string-url "^2.4.1" + socks "^2.6.1" + optionalDependencies: + saslprep "^1.0.3" + mongodb@3.6.3: version "3.6.3" resolved "https://registry.yarnpkg.com/mongodb/-/mongodb-3.6.3.tgz#eddaed0cc3598474d7a15f0f2a5b04848489fd05" @@ -9498,6 +9678,43 @@ mongodb@3.6.3: optionalDependencies: saslprep "^1.0.0" +mongodb@4.3.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/mongodb/-/mongodb-4.3.1.tgz#e346f76e421ec6f47ddea5c8f5140e6181aaeb94" + integrity sha512-sNa8APSIk+r4x31ZwctKjuPSaeKuvUeNb/fu/3B6dRM02HpEgig7hTHM8A/PJQTlxuC/KFWlDlQjhsk/S43tBg== + dependencies: + bson "^4.6.1" + denque "^2.0.1" + mongodb-connection-string-url "^2.4.1" + socks "^2.6.1" + optionalDependencies: + saslprep "^1.0.3" + +mongoose@*: + version "6.2.4" + resolved "https://registry.yarnpkg.com/mongoose/-/mongoose-6.2.4.tgz#c6ff4f84ab47b6c760e773424b0fd1f392d98563" + integrity sha512-3hA3IGxBzZdlp1+/I9qn53NjEAd01qvKAH2WUCPahjVO8+uAmR0B4m+1bC3x9a4r0ExY8QYQ2ryG3E/v5Tj+jA== + dependencies: + bson "^4.2.2" + kareem "2.3.4" + mongodb "4.3.1" + mpath "0.8.4" + mquery "4.0.2" + ms "2.1.3" + sift "16.0.0" + +mpath@0.8.4: + version "0.8.4" + resolved "https://registry.yarnpkg.com/mpath/-/mpath-0.8.4.tgz#6b566d9581621d9e931dd3b142ed3618e7599313" + integrity sha512-DTxNZomBcTWlrMW76jy1wvV37X/cNNxPW1y2Jzd4DZkAaC5ZGsm8bfGfNOthcDuRJujXLqiuS6o3Tpy0JEoh7g== + +mquery@4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/mquery/-/mquery-4.0.2.tgz#a13add5ecd7c2e5a67e0f814b3c7acdfb6772804" + integrity sha512-oAVF0Nil1mT3rxty6Zln4YiD6x6QsUWYz927jZzjMxOK2aqmhEz5JQ7xmrKK7xRFA2dwV+YaOpKU/S+vfNqKxA== + dependencies: + debug "4.x" + mri@1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/mri/-/mri-1.1.4.tgz#7cb1dd1b9b40905f1fac053abe25b6720f44744a" @@ -9518,7 +9735,7 @@ ms@2.1.2, ms@^2.1.1: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@^2.1.3: +ms@2.1.3, ms@^2.1.3: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== @@ -11176,13 +11393,25 @@ redis-info@^3.0.8: dependencies: lodash "^4.17.11" -redis-parser@^3.0.0: +redis-parser@3.0.0, redis-parser@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/redis-parser/-/redis-parser-3.0.0.tgz#b66d828cdcafe6b4b8a428a7def4c6bcac31c8b4" integrity sha1-tm2CjNyv5rS4pCin3vTGvKwxyLQ= dependencies: redis-errors "^1.0.0" +redis@*, redis@4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/redis/-/redis-4.0.4.tgz#b567f82f59086df38433982f7f424b48e924ec7a" + integrity sha512-KaM1OAj/nGrSeybmmOWSMY0LXTGT6FVWgUZZrd2MYzXKJ+VGtqVaciGQeNMfZiQX+kDM8Ke4uttb54m2rm6V0A== + dependencies: + "@node-redis/bloom" "1.0.1" + "@node-redis/client" "1.0.4" + "@node-redis/graph" "1.0.0" + "@node-redis/json" "1.0.2" + "@node-redis/search" "1.0.3" + "@node-redis/time-series" "1.0.2" + regenerate-unicode-properties@^9.0.0: version "9.0.0" resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-9.0.0.tgz#54d09c7115e1f53dc2314a974b32c1c344efe326" @@ -11563,7 +11792,7 @@ sanitize-s3-objectkey@^0.0.1: resolved "https://registry.yarnpkg.com/sanitize-s3-objectkey/-/sanitize-s3-objectkey-0.0.1.tgz#efa9887cd45275b40234fb4bb12fc5754fe64e7e" integrity sha512-ZTk7aqLxy4sD40GWcYWoLfbe05XLmkKvh6vGKe13ADlei24xlezcvjgKy1qRArlaIbIMYaqK7PCalvZtulZlaQ== -saslprep@^1.0.0: +saslprep@^1.0.0, saslprep@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/saslprep/-/saslprep-1.0.3.tgz#4c02f946b56cf54297e347ba1093e7acac4cf226" integrity sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag== @@ -11757,6 +11986,11 @@ side-channel@^1.0.4: get-intrinsic "^1.0.2" object-inspect "^1.9.0" +sift@16.0.0: + version "16.0.0" + resolved "https://registry.yarnpkg.com/sift/-/sift-16.0.0.tgz#447991577db61f1a8fab727a8a98a6db57a23eb8" + integrity sha512-ILTjdP2Mv9V1kIxWMXeMTIRbOBrqKc4JAXmFMnFq3fKeyQ2Qwa3Dw1ubcye3vR+Y6ofA0b9gNDr/y2t6eUeIzQ== + sigmund@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590" @@ -11819,6 +12053,11 @@ slice-ansi@^2.1.0: astral-regex "^1.0.0" is-fullwidth-code-point "^2.0.0" +smart-buffer@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.2.0.tgz#6e1d71fa4f18c05f7d0ff216dd16a481d0e8d9ae" + integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg== + snapdragon-node@^2.0.1: version "2.1.1" resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" @@ -11849,6 +12088,14 @@ snapdragon@^0.8.1: source-map-resolve "^0.5.0" use "^3.1.0" +socks@^2.6.1: + version "2.6.2" + resolved "https://registry.yarnpkg.com/socks/-/socks-2.6.2.tgz#ec042d7960073d40d94268ff3bb727dc685f111a" + integrity sha512-zDZhHhZRY9PxRruRMR7kMhnf3I8hDs4S3f9RecfnGxvcBHQcKcIH/oUcEWffsfl1XxdYlA7nnlGbbTvPz9D8gA== + dependencies: + ip "^1.1.5" + smart-buffer "^4.2.0" + sonic-boom@^1.0.2: version "1.4.1" resolved "https://registry.yarnpkg.com/sonic-boom/-/sonic-boom-1.4.1.tgz#d35d6a74076624f12e6f917ade7b9d75e918f53e" @@ -12829,6 +13076,13 @@ tr46@^2.1.0: dependencies: punycode "^2.1.1" +tr46@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-3.0.0.tgz#555c4e297a950617e8eeddef633c87d4d9d6cbf9" + integrity sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA== + dependencies: + punycode "^2.1.1" + tr46@~0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" @@ -13358,6 +13612,11 @@ webidl-conversions@^6.1.0: resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-6.1.0.tgz#9111b4d7ea80acd40f5270d666621afa78b69514" integrity sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w== +webidl-conversions@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-7.0.0.tgz#256b4e1882be7debbf01d05f0aa2039778ea080a" + integrity sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g== + webpack-cli@^4.9.1: version "4.9.1" resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-4.9.1.tgz#b64be825e2d1b130f285c314caa3b1ba9a4632b3" @@ -13439,6 +13698,14 @@ whatwg-mimetype@^2.1.0, whatwg-mimetype@^2.2.0, whatwg-mimetype@^2.3.0: resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf" integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g== +whatwg-url@^11.0.0: + version "11.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-11.0.0.tgz#0a849eebb5faf2119b901bb76fd795c2848d4018" + integrity sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ== + dependencies: + tr46 "^3.0.0" + webidl-conversions "^7.0.0" + whatwg-url@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" @@ -13712,16 +13979,16 @@ y18n@^5.0.5: resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== +yallist@4.0.0, yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + yallist@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= -yallist@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" - integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== - yaml@2.0.0-1: version "2.0.0-1" resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.0.0-1.tgz#8c3029b3ee2028306d5bcf396980623115ff8d18" diff --git a/packages/string-templates/package.json b/packages/string-templates/package.json index dc5cc078d6..0ff88911b8 100644 --- a/packages/string-templates/package.json +++ b/packages/string-templates/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/string-templates", - "version": "1.0.79-alpha.7", + "version": "1.0.80-alpha.1", "description": "Handlebars wrapper for Budibase templating.", "main": "src/index.cjs", "module": "dist/bundle.mjs", diff --git a/packages/string-templates/src/index.cjs b/packages/string-templates/src/index.cjs index 9584374880..d0de680aca 100644 --- a/packages/string-templates/src/index.cjs +++ b/packages/string-templates/src/index.cjs @@ -18,7 +18,7 @@ module.exports.processObject = templates.processObject module.exports.doesContainStrings = templates.doesContainStrings module.exports.doesContainString = templates.doesContainString module.exports.disableEscaping = templates.disableEscaping -module.exports.findAllBindings = templates.findAllBindings +module.exports.findHBSBlocks = templates.findHBSBlocks /** * Use vm2 to run JS scripts in a node env diff --git a/packages/string-templates/src/index.js b/packages/string-templates/src/index.js index 76ad979670..6e464c27c4 100644 --- a/packages/string-templates/src/index.js +++ b/packages/string-templates/src/index.js @@ -3,7 +3,11 @@ const { registerAll, registerMinimum } = require("./helpers/index") const processors = require("./processors") const { atob, btoa } = require("./utilities") const manifest = require("../manifest.json") -const { FIND_HBS_REGEX, findDoubleHbsInstances } = require("./utilities") +const { + FIND_HBS_REGEX, + FIND_ANY_HBS_REGEX, + findDoubleHbsInstances, +} = require("./utilities") const hbsInstance = handlebars.create() registerAll(hbsInstance) @@ -310,6 +314,21 @@ module.exports.doesContainStrings = (template, strings) => { return false } +/** + * Given a string, this will return any {{ binding }} or {{{ binding }}} type + * statements. + * @param {string} string The string to search within. + * @return {string[]} The found HBS blocks. + */ +module.exports.findHBSBlocks = string => { + let regexp = new RegExp(FIND_ANY_HBS_REGEX) + let matches = string.match(regexp) + if (matches == null) { + return [] + } + return matches +} + /** * This function looks in the supplied template for handlebars instances, if they contain * JS the JS will be decoded and then the supplied string will be looked for. For example @@ -322,12 +341,3 @@ module.exports.doesContainStrings = (template, strings) => { module.exports.doesContainString = (template, string) => { return exports.doesContainStrings(template, [string]) } - -/** - * Finds all regular (double bracketed) expressions inside a string. - * @param string the string to search - * @return {[]} all matching bindings - */ -module.exports.findAllBindings = string => { - return findDoubleHbsInstances(string) -} diff --git a/packages/string-templates/src/index.mjs b/packages/string-templates/src/index.mjs index a9745b3a34..3d115cdec1 100644 --- a/packages/string-templates/src/index.mjs +++ b/packages/string-templates/src/index.mjs @@ -18,7 +18,7 @@ export const processObject = templates.processObject export const doesContainStrings = templates.doesContainStrings export const doesContainString = templates.doesContainString export const disableEscaping = templates.disableEscaping -export const findAllBindings = templates.findAllBindings +export const findHBSBlocks = templates.findHBSBlocks /** * Use polyfilled vm to run JS scripts in a browser Env diff --git a/packages/string-templates/src/utilities.js b/packages/string-templates/src/utilities.js index 0572350d62..775c150e1b 100644 --- a/packages/string-templates/src/utilities.js +++ b/packages/string-templates/src/utilities.js @@ -1,6 +1,7 @@ const ALPHA_NUMERIC_REGEX = /^[A-Za-z0-9]+$/g module.exports.FIND_HBS_REGEX = /{{([^{].*?)}}/g +module.exports.FIND_ANY_HBS_REGEX = /{?{{([^{].*?)}}}?/g module.exports.FIND_TRIPLE_HBS_REGEX = /{{{([^{].*?)}}}/g // originally this could be done with a single regex using look behinds diff --git a/packages/string-templates/test/basic.spec.js b/packages/string-templates/test/basic.spec.js index fbd1c5f440..6c85aa5fa1 100644 --- a/packages/string-templates/test/basic.spec.js +++ b/packages/string-templates/test/basic.spec.js @@ -7,6 +7,7 @@ const { encodeJSBinding, doesContainString, disableEscaping, + findHBSBlocks, } = require("../src/index.cjs") describe("Test that the string processing works correctly", () => { @@ -200,3 +201,13 @@ describe("check that disabling escaping function works", () => { }) }) +describe("check find hbs blocks function", () => { + it("should find none", () => { + expect(findHBSBlocks("hello there")).toEqual([]) + }) + + it("should find two", () => { + expect(findHBSBlocks("{{ hello }} there {{{ name }}}")).toEqual(["{{ hello }}", "{{{ name }}}"]) + }) +}) + diff --git a/packages/worker/package.json b/packages/worker/package.json index 5414543a79..e9a89a2f9c 100644 --- a/packages/worker/package.json +++ b/packages/worker/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/worker", "email": "hi@budibase.com", - "version": "1.0.79-alpha.7", + "version": "1.0.80-alpha.1", "description": "Budibase background service", "main": "src/index.ts", "repository": { @@ -34,8 +34,8 @@ "author": "Budibase", "license": "GPL-3.0", "dependencies": { - "@budibase/backend-core": "^1.0.79-alpha.7", - "@budibase/string-templates": "^1.0.79-alpha.7", + "@budibase/backend-core": "^1.0.80-alpha.1", + "@budibase/string-templates": "^1.0.80-alpha.1", "@koa/router": "^8.0.0", "@sentry/node": "^6.0.0", "@techpass/passport-openidconnect": "^0.3.0", diff --git a/packages/server/scripts/proxy/generateProxyConfig.js b/scripts/proxy/generateProxyConfig.js similarity index 65% rename from packages/server/scripts/proxy/generateProxyConfig.js rename to scripts/proxy/generateProxyConfig.js index 591b320c70..1abc6240a1 100644 --- a/packages/server/scripts/proxy/generateProxyConfig.js +++ b/scripts/proxy/generateProxyConfig.js @@ -1,30 +1,63 @@ #!/usr/bin/env node const path = require("path") const fs = require("fs") -const { processStringSync } = require("@budibase/string-templates") + +function processStringSync(string, env) { + let output = "" + + // process if statements + let removal = false + for (let line of string.split("\n")) { + if (new RegExp(`{{\/if}}`, "g").test(line)) { + removal = false + continue + } + + if (!removal) { + const match = line.match(new RegExp(`{{#if (.*)}}`)) + if (match) { + const key = match[1] + // check the if statement is true + if (!env[key]) { + removal = true + } + continue + } + output += line + "\n" + } + } + + for (let key in env) { + // replace variables + const rgx = new RegExp(`{{\\s*${key}\\s*}}`, "g") + output = output.replace(rgx, env[key]) + } + + return output +} const Configs = { prod: { - k8s: true, apps: "app-service.budibase.svc.cluster.local", worker: "worker-service.budibase.svc.cluster.local", minio: "minio-service.budibase.svc.cluster.local", couchdb: "budibase-prod-svc-couchdb", + resolver: "kube-dns.kube-system.svc.cluster.local" }, preprod: { - k8s: true, apps: "app-service.budibase.svc.cluster.local", worker: "worker-service.budibase.svc.cluster.local", minio: "minio-service.budibase.svc.cluster.local", couchdb: "budibase-preprod-svc-couchdb", + resolver: "kube-dns.kube-system.svc.cluster.local" }, compose: { - compose: true, apps: "app-service", worker: "worker-service", minio: "minio-service", couchdb: "couchdb-service", watchtower: "watchtower-service", + resolver: "127.0.0.11" }, } @@ -36,7 +69,7 @@ const Commands = { async function init(managementCommand) { const config = Configs[managementCommand] - const hostingPath = path.join(process.cwd(), "..", "..", "hosting") + const hostingPath = path.join(process.cwd(), "hosting") const nginxHbsPath = path.join(hostingPath, "nginx.prod.conf.hbs") const nginxOutputPath = path.join( hostingPath,