Merge branch 'master' of github.com:Budibase/budibase into labday/sqs
This commit is contained in:
commit
5e186b5c8a
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"version": "2.22.12",
|
||||
"version": "2.22.13",
|
||||
"npmClient": "yarn",
|
||||
"packages": [
|
||||
"packages/*",
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 60658a052d2642e5f4a8038e253f771a24f34907
|
||||
Subproject commit 63ce32bca871f0a752323f5f7ebb5ec16bbbacc3
|
|
@ -20,7 +20,7 @@ export async function lookupTenantId(userId: string) {
|
|||
return user.tenantId
|
||||
}
|
||||
|
||||
async function getUserDoc(emailOrId: string): Promise<PlatformUser> {
|
||||
export async function getUserDoc(emailOrId: string): Promise<PlatformUser> {
|
||||
const db = getPlatformDB()
|
||||
return db.get(emailOrId)
|
||||
}
|
||||
|
@ -79,6 +79,17 @@ async function addUserDoc(emailOrId: string, newDocFn: () => PlatformUser) {
|
|||
}
|
||||
}
|
||||
|
||||
export async function addSsoUser(
|
||||
ssoId: string,
|
||||
email: string,
|
||||
userId: string,
|
||||
tenantId: string
|
||||
) {
|
||||
return addUserDoc(ssoId, () =>
|
||||
newUserSsoIdDoc(ssoId, email, userId, tenantId)
|
||||
)
|
||||
}
|
||||
|
||||
export async function addUser(
|
||||
tenantId: string,
|
||||
userId: string,
|
||||
|
@ -91,9 +102,7 @@ export async function addUser(
|
|||
]
|
||||
|
||||
if (ssoId) {
|
||||
promises.push(
|
||||
addUserDoc(ssoId, () => newUserSsoIdDoc(ssoId, email, userId, tenantId))
|
||||
)
|
||||
promises.push(addSsoUser(ssoId, email, userId, tenantId))
|
||||
}
|
||||
|
||||
await Promise.all(promises)
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
import ModalBindableInput from "components/common/bindings/ModalBindableInput.svelte"
|
||||
import CodeEditor from "components/common/CodeEditor/CodeEditor.svelte"
|
||||
import BindingSidePanel from "components/common/bindings/BindingSidePanel.svelte"
|
||||
import { BindingHelpers } from "components/common/bindings/utils"
|
||||
import { BindingHelpers, BindingType } from "components/common/bindings/utils"
|
||||
import {
|
||||
bindingsToCompletions,
|
||||
hbAutocomplete,
|
||||
|
@ -576,6 +576,7 @@
|
|||
{
|
||||
js: true,
|
||||
dontDecode: true,
|
||||
type: BindingType.RUNTIME,
|
||||
}
|
||||
)}
|
||||
mode="javascript"
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
import { decodeJSBinding } from "@budibase/string-templates"
|
||||
import { hbInsert, jsInsert } from "components/common/CodeEditor"
|
||||
|
||||
export const BindingType = {
|
||||
READABLE: "readableBinding",
|
||||
RUNTIME: "runtimeBinding",
|
||||
}
|
||||
|
||||
export class BindingHelpers {
|
||||
constructor(getCaretPosition, insertAtPos, { disableWrapping } = {}) {
|
||||
this.getCaretPosition = getCaretPosition
|
||||
|
@ -25,16 +30,20 @@ export class BindingHelpers {
|
|||
}
|
||||
|
||||
// Adds a data binding to the expression
|
||||
onSelectBinding(value, binding, { js, dontDecode }) {
|
||||
onSelectBinding(
|
||||
value,
|
||||
binding,
|
||||
{ js, dontDecode, type = BindingType.READABLE }
|
||||
) {
|
||||
const { start, end } = this.getCaretPosition()
|
||||
if (js) {
|
||||
const jsVal = dontDecode ? value : decodeJSBinding(value)
|
||||
const insertVal = jsInsert(jsVal, start, end, binding.readableBinding, {
|
||||
const insertVal = jsInsert(jsVal, start, end, binding[type], {
|
||||
disableWrapping: this.disableWrapping,
|
||||
})
|
||||
this.insertAtPos({ start, end, value: insertVal })
|
||||
} else {
|
||||
const insertVal = hbInsert(value, start, end, binding.readableBinding)
|
||||
const insertVal = hbInsert(value, start, end, binding[type])
|
||||
this.insertAtPos({ start, end, value: insertVal })
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import {
|
|||
QueryType,
|
||||
} from "@budibase/types"
|
||||
import { db as dbCore } from "@budibase/backend-core"
|
||||
import { HOST_ADDRESS } from "./utils"
|
||||
|
||||
interface CouchDBConfig {
|
||||
url: string
|
||||
|
@ -28,7 +29,7 @@ const SCHEMA: Integration = {
|
|||
url: {
|
||||
type: DatasourceFieldType.STRING,
|
||||
required: true,
|
||||
default: "http://localhost:5984",
|
||||
default: `http://${HOST_ADDRESS}:5984`,
|
||||
},
|
||||
database: {
|
||||
type: DatasourceFieldType.STRING,
|
||||
|
|
|
@ -8,6 +8,7 @@ import {
|
|||
} from "@budibase/types"
|
||||
|
||||
import { Client, ClientOptions } from "@elastic/elasticsearch"
|
||||
import { HOST_ADDRESS } from "./utils"
|
||||
|
||||
interface ElasticsearchConfig {
|
||||
url: string
|
||||
|
@ -29,7 +30,7 @@ const SCHEMA: Integration = {
|
|||
url: {
|
||||
type: DatasourceFieldType.STRING,
|
||||
required: true,
|
||||
default: "http://localhost:9200",
|
||||
default: `http://${HOST_ADDRESS}:9200`,
|
||||
},
|
||||
ssl: {
|
||||
type: DatasourceFieldType.BOOLEAN,
|
||||
|
|
|
@ -22,6 +22,7 @@ import {
|
|||
finaliseExternalTables,
|
||||
SqlClient,
|
||||
checkExternalTables,
|
||||
HOST_ADDRESS,
|
||||
} from "./utils"
|
||||
import Sql from "./base/sql"
|
||||
import { MSSQLTablesResponse, MSSQLColumn } from "./base/types"
|
||||
|
@ -88,7 +89,6 @@ const SCHEMA: Integration = {
|
|||
user: {
|
||||
type: DatasourceFieldType.STRING,
|
||||
required: true,
|
||||
default: "localhost",
|
||||
},
|
||||
password: {
|
||||
type: DatasourceFieldType.PASSWORD,
|
||||
|
@ -96,7 +96,7 @@ const SCHEMA: Integration = {
|
|||
},
|
||||
server: {
|
||||
type: DatasourceFieldType.STRING,
|
||||
default: "localhost",
|
||||
default: HOST_ADDRESS,
|
||||
},
|
||||
port: {
|
||||
type: DatasourceFieldType.NUMBER,
|
||||
|
|
|
@ -22,6 +22,7 @@ import {
|
|||
InsertManyResult,
|
||||
} from "mongodb"
|
||||
import environment from "../environment"
|
||||
import { HOST_ADDRESS } from "./utils"
|
||||
|
||||
export interface MongoDBConfig {
|
||||
connectionString: string
|
||||
|
@ -51,7 +52,7 @@ const getSchema = () => {
|
|||
connectionString: {
|
||||
type: DatasourceFieldType.STRING,
|
||||
required: true,
|
||||
default: "mongodb://localhost:27017",
|
||||
default: `mongodb://${HOST_ADDRESS}:27017`,
|
||||
display: "Connection string",
|
||||
},
|
||||
db: {
|
||||
|
|
|
@ -22,6 +22,7 @@ import {
|
|||
generateColumnDefinition,
|
||||
finaliseExternalTables,
|
||||
checkExternalTables,
|
||||
HOST_ADDRESS,
|
||||
} from "./utils"
|
||||
import dayjs from "dayjs"
|
||||
import { NUMBER_REGEX } from "../utilities"
|
||||
|
@ -50,7 +51,7 @@ const SCHEMA: Integration = {
|
|||
datasource: {
|
||||
host: {
|
||||
type: DatasourceFieldType.STRING,
|
||||
default: "localhost",
|
||||
default: HOST_ADDRESS,
|
||||
required: true,
|
||||
},
|
||||
port: {
|
||||
|
|
|
@ -22,6 +22,7 @@ import {
|
|||
finaliseExternalTables,
|
||||
getSqlQuery,
|
||||
SqlClient,
|
||||
HOST_ADDRESS,
|
||||
} from "./utils"
|
||||
import Sql from "./base/sql"
|
||||
import {
|
||||
|
@ -63,7 +64,7 @@ const SCHEMA: Integration = {
|
|||
datasource: {
|
||||
host: {
|
||||
type: DatasourceFieldType.STRING,
|
||||
default: "localhost",
|
||||
default: HOST_ADDRESS,
|
||||
required: true,
|
||||
},
|
||||
port: {
|
||||
|
|
|
@ -21,6 +21,7 @@ import {
|
|||
finaliseExternalTables,
|
||||
SqlClient,
|
||||
checkExternalTables,
|
||||
HOST_ADDRESS,
|
||||
} from "./utils"
|
||||
import Sql from "./base/sql"
|
||||
import { PostgresColumn } from "./base/types"
|
||||
|
@ -72,7 +73,7 @@ const SCHEMA: Integration = {
|
|||
datasource: {
|
||||
host: {
|
||||
type: DatasourceFieldType.STRING,
|
||||
default: "localhost",
|
||||
default: HOST_ADDRESS,
|
||||
required: true,
|
||||
},
|
||||
port: {
|
||||
|
|
|
@ -6,6 +6,7 @@ import {
|
|||
QueryType,
|
||||
} from "@budibase/types"
|
||||
import Redis from "ioredis"
|
||||
import { HOST_ADDRESS } from "./utils"
|
||||
|
||||
interface RedisConfig {
|
||||
host: string
|
||||
|
@ -28,7 +29,7 @@ const SCHEMA: Integration = {
|
|||
host: {
|
||||
type: DatasourceFieldType.STRING,
|
||||
required: true,
|
||||
default: "localhost",
|
||||
default: HOST_ADDRESS,
|
||||
},
|
||||
port: {
|
||||
type: DatasourceFieldType.NUMBER,
|
||||
|
|
|
@ -8,6 +8,7 @@ import {
|
|||
import { DocumentType, SEPARATOR } from "../db/utils"
|
||||
import { InvalidColumns, DEFAULT_BB_DATASOURCE_ID } from "../constants"
|
||||
import { helpers } from "@budibase/shared-core"
|
||||
import env from "../environment"
|
||||
|
||||
const DOUBLE_SEPARATOR = `${SEPARATOR}${SEPARATOR}`
|
||||
const ROW_ID_REGEX = /^\[.*]$/g
|
||||
|
@ -88,6 +89,14 @@ export enum SqlClient {
|
|||
SQL_LITE = "sqlite3",
|
||||
}
|
||||
|
||||
const isCloud = env.isProd() && !env.SELF_HOSTED
|
||||
const isSelfHost = env.isProd() && env.SELF_HOSTED
|
||||
export const HOST_ADDRESS = isSelfHost
|
||||
? "host.docker.internal"
|
||||
: isCloud
|
||||
? ""
|
||||
: "localhost"
|
||||
|
||||
export function isExternalTableID(tableId: string) {
|
||||
return tableId.includes(DocumentType.DATASOURCE)
|
||||
}
|
||||
|
|
|
@ -68,6 +68,11 @@ export interface CreateAdminUserRequest {
|
|||
ssoId?: string
|
||||
}
|
||||
|
||||
export interface AddSSoUserRequest {
|
||||
ssoId: string
|
||||
email: string
|
||||
}
|
||||
|
||||
export interface CreateAdminUserResponse {
|
||||
_id: string
|
||||
_rev: string
|
||||
|
|
|
@ -3,6 +3,7 @@ import env from "../../../environment"
|
|||
import {
|
||||
AcceptUserInviteRequest,
|
||||
AcceptUserInviteResponse,
|
||||
AddSSoUserRequest,
|
||||
BulkUserRequest,
|
||||
BulkUserResponse,
|
||||
CloudAccount,
|
||||
|
@ -15,6 +16,7 @@ import {
|
|||
LockName,
|
||||
LockType,
|
||||
MigrationType,
|
||||
PlatformUserByEmail,
|
||||
SaveUserResponse,
|
||||
SearchUsersRequest,
|
||||
User,
|
||||
|
@ -53,6 +55,25 @@ export const save = async (ctx: UserCtx<User, SaveUserResponse>) => {
|
|||
}
|
||||
}
|
||||
|
||||
export const addSsoSupport = async (ctx: Ctx<AddSSoUserRequest>) => {
|
||||
const { email, ssoId } = ctx.request.body
|
||||
try {
|
||||
// Status is changed to 404 from getUserDoc if user is not found
|
||||
let userByEmail = (await platform.users.getUserDoc(
|
||||
email
|
||||
)) as PlatformUserByEmail
|
||||
await platform.users.addSsoUser(
|
||||
ssoId,
|
||||
email,
|
||||
userByEmail.userId,
|
||||
userByEmail.tenantId
|
||||
)
|
||||
ctx.status = 200
|
||||
} catch (err: any) {
|
||||
ctx.throw(err.status || 400, err)
|
||||
}
|
||||
}
|
||||
|
||||
const bulkDelete = async (userIds: string[], currentUserId: string) => {
|
||||
if (userIds?.indexOf(currentUserId) !== -1) {
|
||||
throw new Error("Unable to delete self.")
|
||||
|
|
|
@ -41,6 +41,10 @@ const PUBLIC_ENDPOINTS = [
|
|||
route: "/api/global/users/init",
|
||||
method: "POST",
|
||||
},
|
||||
{
|
||||
route: "/api/global/users/sso",
|
||||
method: "POST",
|
||||
},
|
||||
{
|
||||
route: "/api/global/users/invite/accept",
|
||||
method: "POST",
|
||||
|
@ -81,6 +85,11 @@ const NO_TENANCY_ENDPOINTS = [
|
|||
route: "/api/global/users/init",
|
||||
method: "POST",
|
||||
},
|
||||
// tenant is retrieved from the user found by the requested email
|
||||
{
|
||||
route: "/api/global/users/sso",
|
||||
method: "POST",
|
||||
},
|
||||
// deprecated single tenant sso callback
|
||||
{
|
||||
route: "/api/admin/auth/google/callback",
|
||||
|
|
|
@ -520,10 +520,51 @@ describe("/api/global/users", () => {
|
|||
})
|
||||
}
|
||||
|
||||
function createPasswordUser() {
|
||||
return config.doInTenant(() => {
|
||||
const user = structures.users.user()
|
||||
return userSdk.db.save(user)
|
||||
})
|
||||
}
|
||||
|
||||
it("should be able to update an sso user that has no password", async () => {
|
||||
const user = await createSSOUser()
|
||||
await config.api.users.saveUser(user)
|
||||
})
|
||||
|
||||
it("sso support couldn't be used by admin. It is cloud restricted and needs internal key", async () => {
|
||||
const user = await config.createUser()
|
||||
const ssoId = "fake-ssoId"
|
||||
await config.api.users
|
||||
.addSsoSupportDefaultAuth(ssoId, user.email)
|
||||
.expect("Content-Type", /json/)
|
||||
.expect(403)
|
||||
})
|
||||
|
||||
it("if user email doesn't exist, SSO support couldn't be added. Not found error returned", async () => {
|
||||
const ssoId = "fake-ssoId"
|
||||
const email = "fake-email@budibase.com"
|
||||
await config.api.users
|
||||
.addSsoSupportInternalAPIAuth(ssoId, email)
|
||||
.expect("Content-Type", /json/)
|
||||
.expect(404)
|
||||
})
|
||||
|
||||
it("if user email exist, SSO support is added", async () => {
|
||||
const user = await createPasswordUser()
|
||||
const ssoId = "fakessoId"
|
||||
await config.api.users
|
||||
.addSsoSupportInternalAPIAuth(ssoId, user.email)
|
||||
.expect(200)
|
||||
})
|
||||
|
||||
it("if user ssoId is already assigned, no change will be applied", async () => {
|
||||
const user = await createSSOUser()
|
||||
user.ssoId = "testssoId"
|
||||
await config.api.users
|
||||
.addSsoSupportInternalAPIAuth(user.ssoId, user.email)
|
||||
.expect(200)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
|
|
|
@ -65,6 +65,12 @@ router
|
|||
users.buildUserSaveValidation(),
|
||||
controller.save
|
||||
)
|
||||
.post(
|
||||
"/api/global/users/sso",
|
||||
cloudRestricted,
|
||||
users.buildAddSsoSupport(),
|
||||
controller.addSsoSupport
|
||||
)
|
||||
.post(
|
||||
"/api/global/users/bulk",
|
||||
auth.adminOnly,
|
||||
|
|
|
@ -41,6 +41,15 @@ export const buildUserSaveValidation = () => {
|
|||
return auth.joiValidator.body(Joi.object(schema).required().unknown(true))
|
||||
}
|
||||
|
||||
export const buildAddSsoSupport = () => {
|
||||
return auth.joiValidator.body(
|
||||
Joi.object({
|
||||
ssoId: Joi.string().required(),
|
||||
email: Joi.string().required(),
|
||||
}).required()
|
||||
)
|
||||
}
|
||||
|
||||
export const buildUserBulkUserValidation = (isSelf = false) => {
|
||||
if (!isSelf) {
|
||||
schema = {
|
||||
|
|
|
@ -127,6 +127,20 @@ export class UserAPI extends TestAPI {
|
|||
.expect(status ? status : 200)
|
||||
}
|
||||
|
||||
addSsoSupportInternalAPIAuth = (ssoId: string, email: string) => {
|
||||
return this.request
|
||||
.post(`/api/global/users/sso`)
|
||||
.send({ ssoId, email })
|
||||
.set(this.config.internalAPIHeaders())
|
||||
}
|
||||
|
||||
addSsoSupportDefaultAuth = (ssoId: string, email: string) => {
|
||||
return this.request
|
||||
.post(`/api/global/users/sso`)
|
||||
.send({ ssoId, email })
|
||||
.set(this.config.defaultHeaders())
|
||||
}
|
||||
|
||||
deleteUser = (userId: string, status?: number) => {
|
||||
return this.request
|
||||
.delete(`/api/global/users/${userId}`)
|
||||
|
|
Loading…
Reference in New Issue