Merge pull request #2985 from Budibase/fix/postrelease

Fix/postrelease
This commit is contained in:
Martin McKeaveney 2021-10-13 13:01:16 +01:00 committed by GitHub
commit bfe7bdf02e
12 changed files with 102 additions and 16 deletions

View File

@ -42,8 +42,9 @@ module.exports = (
internal = false internal = false
if (authCookie) { if (authCookie) {
let error = null let error = null
const sessionId = authCookie.sessionId, const sessionId = authCookie.sessionId
userId = authCookie.userId const userId = authCookie.userId
const session = await getSession(userId, sessionId) const session = await getSession(userId, sessionId)
if (!session) { if (!session) {
error = "No session found" error = "No session found"

View File

@ -24,17 +24,24 @@ exports.createASession = async (userId, session) => {
await client.store(makeSessionID(userId, sessionId), session, EXPIRY_SECONDS) await client.store(makeSessionID(userId, sessionId), session, EXPIRY_SECONDS)
} }
exports.invalidateSessions = async (userId, sessionId = null) => { exports.invalidateSessions = async (userId, sessionIds = null) => {
let sessions = [] let sessions = []
if (sessionId) {
sessions.push({ key: makeSessionID(userId, sessionId) }) // If no sessionIds, get all the sessions for the user
} else { if (!sessionIds) {
sessions = await getSessionsForUser(userId) sessions = await getSessionsForUser(userId)
sessions.forEach( sessions.forEach(
session => session =>
(session.key = makeSessionID(session.userId, session.sessionId)) (session.key = makeSessionID(session.userId, session.sessionId))
) )
} else {
// use the passed array of sessionIds
sessions = Array.isArray(sessionIds) ? sessionIds : [sessionIds]
sessions = sessions.map(sessionId => ({
key: makeSessionID(userId, sessionId),
}))
} }
const client = await redis.getSessionClient() const client = await redis.getSessionClient()
const promises = [] const promises = []
for (let session of sessions) { for (let session of sessions) {

View File

@ -7,7 +7,7 @@ const {
const jwt = require("jsonwebtoken") const jwt = require("jsonwebtoken")
const { options } = require("./middleware/passport/jwt") const { options } = require("./middleware/passport/jwt")
const { createUserEmailView } = require("./db/views") const { createUserEmailView } = require("./db/views")
const { Headers, UserStatus } = require("./constants") const { Headers, UserStatus, Cookies } = require("./constants")
const { const {
getGlobalDB, getGlobalDB,
updateTenantId, updateTenantId,
@ -19,6 +19,7 @@ const accounts = require("./cloud/accounts")
const { hash } = require("./hashing") const { hash } = require("./hashing")
const userCache = require("./cache/user") const userCache = require("./cache/user")
const env = require("./environment") const env = require("./environment")
const { getUserSessions, invalidateSessions } = require("./security/sessions")
const APP_PREFIX = DocumentTypes.APP + SEPARATOR const APP_PREFIX = DocumentTypes.APP + SEPARATOR
@ -235,3 +236,28 @@ exports.saveUser = async (
} }
} }
} }
/**
* Logs a user out from budibase. Re-used across account portal and builder.
*/
exports.platformLogout = async ({ ctx, userId, keepActiveSession }) => {
if (!ctx) throw new Error("Koa context must be supplied to logout.")
const currentSession = this.getCookie(ctx, Cookies.Auth)
let sessions = await getUserSessions(userId)
if (keepActiveSession) {
sessions = sessions.filter(
session => session.sessionId !== currentSession.sessionId
)
} else {
// clear cookies
this.clearCookie(ctx, Cookies.Auth)
this.clearCookie(ctx, Cookies.CurrentApp)
}
await invalidateSessions(
userId,
sessions.map(({ sessionId }) => sessionId)
)
}

View File

@ -32,6 +32,7 @@
const FORMULA_TYPE = FIELDS.FORMULA.type const FORMULA_TYPE = FIELDS.FORMULA.type
const LINK_TYPE = FIELDS.LINK.type const LINK_TYPE = FIELDS.LINK.type
const dispatch = createEventDispatcher() const dispatch = createEventDispatcher()
const PROHIBITED_COLUMN_NAMES = ["type", "_id", "_rev", "tableId"]
const { hide } = getContext(Context.Modal) const { hide } = getContext(Context.Modal)
let fieldDefinitions = cloneDeep(FIELDS) let fieldDefinitions = cloneDeep(FIELDS)
@ -66,6 +67,10 @@
(field.type === LINK_TYPE && !field.tableId) || (field.type === LINK_TYPE && !field.tableId) ||
Object.keys($tables.draft?.schema ?? {}).some( Object.keys($tables.draft?.schema ?? {}).some(
key => key !== originalName && key === field.name key => key !== originalName && key === field.name
) ||
columnNameInvalid
$: columnNameInvalid = PROHIBITED_COLUMN_NAMES.some(
name => field.name === name
) )
// used to select what different options can be displayed for column type // used to select what different options can be displayed for column type
@ -200,6 +205,9 @@
label="Name" label="Name"
bind:value={field.name} bind:value={field.name}
disabled={uneditable || (linkEditDisabled && field.type === LINK_TYPE)} disabled={uneditable || (linkEditDisabled && field.type === LINK_TYPE)}
error={columnNameInvalid
? `${PROHIBITED_COLUMN_NAMES.join(", ")} are not allowed as column names`
: ""}
/> />
<Select <Select

View File

@ -1,10 +1,18 @@
<script> <script>
import { Label, Input, Layout, Toggle, Button } from "@budibase/bbui" import {
Label,
Input,
Layout,
Toggle,
Button,
TextArea,
} from "@budibase/bbui"
import KeyValueBuilder from "components/integration/KeyValueBuilder.svelte" import KeyValueBuilder from "components/integration/KeyValueBuilder.svelte"
import { capitalise } from "helpers" import { capitalise } from "helpers"
export let integration export let integration
export let schema export let schema
let addButton let addButton
</script> </script>
@ -29,6 +37,15 @@
<Label>{capitalise(configKey)}</Label> <Label>{capitalise(configKey)}</Label>
<Toggle text="" bind:value={integration[configKey]} /> <Toggle text="" bind:value={integration[configKey]} />
</div> </div>
{:else if schema[configKey].type === "longForm"}
<div class="form-row">
<Label>{capitalise(configKey)}</Label>
<TextArea
type={schema[configKey].type}
on:change
bind:value={integration[configKey]}
/>
</div>
{:else} {:else}
<div class="form-row"> <div class="form-row">
<Label>{capitalise(configKey)}</Label> <Label>{capitalise(configKey)}</Label>

View File

@ -60,7 +60,7 @@
</Modal> </Modal>
<Modal bind:this={externalDatasourceModal}> <Modal bind:this={externalDatasourceModal}>
<DatasourceConfigModal {integration} /> <DatasourceConfigModal {integration} {modal} />
</Modal> </Modal>
<Modal bind:this={modal}> <Modal bind:this={modal}>

View File

@ -64,7 +64,7 @@
? "Fetch tables from database" ? "Fetch tables from database"
: "Save and continue to query"} : "Save and continue to query"}
cancelText="Back" cancelText="Back"
size="M" size="L"
> >
<Layout noPadding> <Layout noPadding>
<Body size="XS" <Body size="XS"

View File

@ -77,7 +77,7 @@ exports.run = async function ({ inputs }) {
const { status, message } = await getFetchResponse(response) const { status, message } = await getFetchResponse(response)
return { return {
httpStatus: status, httpStatus: status,
success: status === 200, success: status === 200 || status === 204,
response: message, response: message,
} }
} }

View File

@ -20,12 +20,14 @@ export enum QueryTypes {
export enum DatasourceFieldTypes { export enum DatasourceFieldTypes {
STRING = "string", STRING = "string",
LONGFORM = "longForm",
BOOLEAN = "boolean", BOOLEAN = "boolean",
NUMBER = "number", NUMBER = "number",
PASSWORD = "password", PASSWORD = "password",
LIST = "list", LIST = "list",
OBJECT = "object", OBJECT = "object",
JSON = "json", JSON = "json",
FILE = "file",
} }
export enum SourceNames { export enum SourceNames {

View File

@ -28,6 +28,8 @@ module PostgresModule {
user: string user: string
password: string password: string
ssl?: boolean ssl?: boolean
ca?: string
rejectUnauthorized?: boolean
} }
const SCHEMA: Integration = { const SCHEMA: Integration = {
@ -67,6 +69,16 @@ module PostgresModule {
default: false, default: false,
required: false, required: false,
}, },
rejectUnauthorized: {
type: DatasourceFieldTypes.BOOLEAN,
default: false,
required: false,
},
ca: {
type: DatasourceFieldTypes.LONGFORM,
default: false,
required: false,
},
}, },
query: { query: {
create: { create: {
@ -144,7 +156,12 @@ module PostgresModule {
let newConfig = { let newConfig = {
...this.config, ...this.config,
ssl: this.config.ssl ? { rejectUnauthorized: true } : undefined, ssl: this.config.ssl
? {
rejectUnauthorized: this.config.rejectUnauthorized,
ca: this.config.ca,
}
: undefined,
} }
if (!this.pool) { if (!this.pool) {
this.pool = new Pool(newConfig) this.pool = new Pool(newConfig)

View File

@ -14,6 +14,7 @@ const {
isMultiTenant, isMultiTenant,
} = require("@budibase/auth/tenancy") } = require("@budibase/auth/tenancy")
const env = require("../../../environment") const env = require("../../../environment")
const { platformLogout } = require("../../../../../auth/src/utils")
function googleCallbackUrl(config) { function googleCallbackUrl(config) {
// incase there is a callback URL from before // incase there is a callback URL from before
@ -121,8 +122,7 @@ exports.resetUpdate = async ctx => {
} }
exports.logout = async ctx => { exports.logout = async ctx => {
clearCookie(ctx, Cookies.Auth) await platformLogout({ ctx, userId: ctx.user._id })
clearCookie(ctx, Cookies.CurrentApp)
ctx.body = { message: "User logged out." } ctx.body = { message: "User logged out." }
} }

View File

@ -3,7 +3,8 @@ const {
StaticDatabases, StaticDatabases,
generateNewUsageQuotaDoc, generateNewUsageQuotaDoc,
} = require("@budibase/auth/db") } = require("@budibase/auth/db")
const { hash, getGlobalUserByEmail, saveUser } = require("@budibase/auth").utils const { hash, getGlobalUserByEmail, saveUser, platformLogout } =
require("@budibase/auth").utils
const { EmailTemplatePurpose } = require("../../../constants") const { EmailTemplatePurpose } = require("../../../constants")
const { checkInviteCode } = require("../../../utilities/redis") const { checkInviteCode } = require("../../../utilities/redis")
const { sendEmail } = require("../../../utilities/email") const { sendEmail } = require("../../../utilities/email")
@ -173,7 +174,14 @@ exports.updateSelf = async ctx => {
const db = getGlobalDB() const db = getGlobalDB()
const user = await db.get(ctx.user._id) const user = await db.get(ctx.user._id)
if (ctx.request.body.password) { if (ctx.request.body.password) {
// changing password
ctx.request.body.password = await hash(ctx.request.body.password) ctx.request.body.password = await hash(ctx.request.body.password)
// Log all other sessions out apart from the current one
await platformLogout({
ctx,
userId: ctx.user._id,
keepActiveSession: true,
})
} }
// don't allow sending up an ID/Rev, always use the existing one // don't allow sending up an ID/Rev, always use the existing one
delete ctx.request.body._id delete ctx.request.body._id