diff --git a/packages/server/src/api/controllers/datasource.ts b/packages/server/src/api/controllers/datasource.ts index fb70bebbd2..469cd29b56 100644 --- a/packages/server/src/api/controllers/datasource.ts +++ b/packages/server/src/api/controllers/datasource.ts @@ -14,6 +14,7 @@ import { invalidateDynamicVariables } from "../../threads/utils" import { db as dbCore, context, events } from "@budibase/backend-core" import { UserCtx, Datasource, Row } from "@budibase/types" import sdk from "../../sdk" +import { mergeConfigs } from "../../sdk/app/datasources/datasources" export async function fetch(ctx: UserCtx) { // Get internal tables @@ -158,7 +159,10 @@ export async function update(ctx: UserCtx) { ? { name: ctx.request.body?.name } : ctx.request.body - datasource = { ...datasource, ...dataSourceBody } + datasource = { + ...datasource, + ...sdk.datasources.mergeConfigs(dataSourceBody, datasource), + } if (auth && !ctx.request.body.auth) { // don't strip auth config from DB datasource.config!.auth = auth diff --git a/packages/server/src/api/routes/tests/datasource.spec.ts b/packages/server/src/api/routes/tests/datasource.spec.ts index 66888023c4..cad8009dae 100644 --- a/packages/server/src/api/routes/tests/datasource.spec.ts +++ b/packages/server/src/api/routes/tests/datasource.spec.ts @@ -2,7 +2,8 @@ jest.mock("pg") import * as setup from "./utilities" import { checkBuilderEndpoint } from "./utilities/TestFunctions" import { checkCacheForDynamicVariable } from "../../../threads/utils" -import { events } from "@budibase/backend-core" +import { context, events } from "@budibase/backend-core" +import sdk from "../../../sdk" let { basicDatasource } = setup.structures const pg = require("pg") @@ -184,4 +185,37 @@ describe("/datasources", () => { }) }) }) + + describe("check secret replacement", () => { + async function makeDatasource() { + datasource = basicDatasource() + datasource.datasource.config.password = "testing" + const res = await request + .post(`/api/datasources`) + .send(datasource) + .set(config.defaultHeaders()) + .expect("Content-Type", /json/) + .expect(200) + return res.body.datasource + } + + it("should save a datasource with password", async () => { + const datasource = await makeDatasource() + expect(datasource.config.password).toBe("--secret-value--") + }) + + it("should not the password on update with the --secret-value--", async () => { + const datasource = await makeDatasource() + await request + .put(`/api/datasources/${datasource._id}`) + .send(datasource) + .set(config.defaultHeaders()) + .expect("Content-Type", /json/) + .expect(200) + await context.doInAppContext(config.getAppId(), async () => { + const dbDatasource: any = await sdk.datasources.get(datasource._id) + expect(dbDatasource.config.password).toBe("testing") + }) + }) + }) }) diff --git a/packages/server/src/sdk/app/datasources/datasources.ts b/packages/server/src/sdk/app/datasources/datasources.ts index 4a3880b7b9..7a324b86f9 100644 --- a/packages/server/src/sdk/app/datasources/datasources.ts +++ b/packages/server/src/sdk/app/datasources/datasources.ts @@ -79,3 +79,20 @@ export async function removeSecrets(datasources: Datasource[]) { export async function removeSecretSingle(datasource: Datasource) { return (await removeSecrets([datasource]))[0] } + +export function mergeConfigs(update: Datasource, old: Datasource) { + if (!update.config) { + return update + } + for (let [key, value] of Object.entries(update.config)) { + if (value !== PASSWORD_REPLACEMENT) { + continue + } + if (old.config?.[key]) { + update.config[key] = old.config?.[key] + } else { + delete update.config[key] + } + } + return update +}