Disabling js interop in Typescript build of backend-core and worker, fixing build issues.

This commit is contained in:
mike12345567 2022-11-26 14:46:01 +00:00
parent 3ce9df0d25
commit 90362b65c1
19 changed files with 296 additions and 275 deletions

View File

@ -2,3 +2,4 @@ export * as generic from "./generic"
export * as user from "./user"
export * as app from "./appMetadata"
export * as writethrough from "./writethrough"
export * from "./generic"

View File

@ -2,22 +2,21 @@ import {
IdentityContext,
IdentityType,
User,
UserContext,
isCloudAccount,
Account,
AccountUserContext,
} from "@budibase/types"
import * as context from "."
export const getIdentity = (): IdentityContext | undefined => {
export function getIdentity(): IdentityContext | undefined {
return context.getIdentity()
}
export const doInIdentityContext = (identity: IdentityContext, task: any) => {
export function doInIdentityContext(identity: IdentityContext, task: any) {
return context.doInIdentityContext(identity, task)
}
export const doInUserContext = (user: User, task: any) => {
export function doInUserContext(user: User, task: any) {
const userContext: any = {
...user,
_id: user._id as string,
@ -26,7 +25,7 @@ export const doInUserContext = (user: User, task: any) => {
return doInIdentityContext(userContext, task)
}
export const doInAccountContext = (account: Account, task: any) => {
export function doInAccountContext(account: Account, task: any) {
const _id = getAccountUserId(account)
const tenantId = account.tenantId
const accountContext: AccountUserContext = {
@ -38,12 +37,12 @@ export const doInAccountContext = (account: Account, task: any) => {
return doInIdentityContext(accountContext, task)
}
export const getAccountUserId = (account: Account) => {
export function getAccountUserId(account: Account) {
let userId: string
if (isCloudAccount(account)) {
userId = account.budibaseUserId
} else {
// use account id as user id for self hosting
// use account id as user id for self-hosting
userId = account.accountId
}
return userId

View File

@ -1,223 +1,3 @@
import env from "../environment"
import {
SEPARATOR,
DocumentType,
getDevelopmentAppID,
getProdAppID,
baseGlobalDBName,
getDB,
} from "../db"
import Context from "./Context"
import { IdentityContext, Database } from "@budibase/types"
import { DEFAULT_TENANT_ID as _DEFAULT_TENANT_ID } from "../constants"
import { ContextMap } from "./constants"
export const DEFAULT_TENANT_ID = _DEFAULT_TENANT_ID
// some test cases call functions directly, need to
// store an app ID to pretend there is a context
let TEST_APP_ID: string | null = null
export function isMultiTenant() {
return env.MULTI_TENANCY
}
export function isTenantIdSet() {
const context = Context.get()
return !!context?.tenantId
}
export function isTenancyEnabled() {
return env.MULTI_TENANCY
}
/**
* Given an app ID this will attempt to retrieve the tenant ID from it.
* @return {null|string} The tenant ID found within the app ID.
*/
export function getTenantIDFromAppID(appId: string) {
if (!appId) {
return undefined
}
if (!isMultiTenant()) {
return DEFAULT_TENANT_ID
}
const split = appId.split(SEPARATOR)
const hasDev = split[1] === DocumentType.DEV
if ((hasDev && split.length === 3) || (!hasDev && split.length === 2)) {
return undefined
}
if (hasDev) {
return split[2]
} else {
return split[1]
}
}
function updateContext(updates: ContextMap) {
let context: ContextMap
try {
context = Context.get()
} catch (err) {
// no context, start empty
context = {}
}
context = {
...context,
...updates,
}
return context
}
async function newContext(updates: ContextMap, task: any) {
// see if there already is a context setup
let context: ContextMap = updateContext(updates)
return Context.run(context, task)
}
export async function doInContext(appId: string, task: any): Promise<any> {
const tenantId = getTenantIDFromAppID(appId)
return newContext(
{
tenantId,
appId,
},
task
)
}
export async function doInTenant(
tenantId: string | null,
task: any
): Promise<any> {
// make sure default always selected in single tenancy
if (!env.MULTI_TENANCY) {
tenantId = tenantId || DEFAULT_TENANT_ID
}
const updates = tenantId ? { tenantId } : {}
return newContext(updates, task)
}
export async function doInAppContext(appId: string, task: any): Promise<any> {
if (!appId) {
throw new Error("appId is required")
}
const tenantId = getTenantIDFromAppID(appId)
const updates: ContextMap = { appId }
if (tenantId) {
updates.tenantId = tenantId
}
return newContext(updates, task)
}
export async function doInIdentityContext(
identity: IdentityContext,
task: any
): Promise<any> {
if (!identity) {
throw new Error("identity is required")
}
const context: ContextMap = {
identity,
}
if (identity.tenantId) {
context.tenantId = identity.tenantId
}
return newContext(context, task)
}
export function getIdentity(): IdentityContext | undefined {
try {
const context = Context.get()
return context?.identity
} catch (e) {
// do nothing - identity is not in context
}
}
export function getTenantId(): string {
if (!isMultiTenant()) {
return DEFAULT_TENANT_ID
}
const context = Context.get()
const tenantId = context?.tenantId
if (!tenantId) {
throw new Error("Tenant id not found")
}
return tenantId
}
export function getAppId(): string | undefined {
const context = Context.get()
const foundId = context?.appId
if (!foundId && env.isTest() && TEST_APP_ID) {
return TEST_APP_ID
} else {
return foundId
}
}
export function updateTenantId(tenantId?: string) {
let context: ContextMap = updateContext({
tenantId,
})
Context.set(context)
}
export function updateAppId(appId: string) {
let context: ContextMap = updateContext({
appId,
})
try {
Context.set(context)
} catch (err) {
if (env.isTest()) {
TEST_APP_ID = appId
} else {
throw err
}
}
}
export function getGlobalDB(): Database {
const context = Context.get()
if (!context || (env.MULTI_TENANCY && !context.tenantId)) {
throw new Error("Global DB not found")
}
return getDB(baseGlobalDBName(context?.tenantId))
}
/**
* Gets the app database based on whatever the request
* contained, dev or prod.
*/
export function getAppDB(opts?: any): Database {
const appId = getAppId()
return getDB(appId, opts)
}
/**
* This specifically gets the prod app ID, if the request
* contained a development app ID, this will get the prod one.
*/
export function getProdAppDB(opts?: any): Database {
const appId = getAppId()
if (!appId) {
throw new Error("Unable to retrieve prod DB - no app ID.")
}
return getDB(getProdAppID(appId), opts)
}
/**
* This specifically gets the dev app ID, if the request
* contained a prod app ID, this will get the dev one.
*/
export function getDevAppDB(opts?: any): Database {
const appId = getAppId()
if (!appId) {
throw new Error("Unable to retrieve dev DB - no app ID.")
}
return getDB(getDevelopmentAppID(appId), opts)
}
export { DEFAULT_TENANT_ID } from "../constants"
export * as identity from "./identity"
export * from "./mainContext"

View File

@ -0,0 +1,222 @@
// some test cases call functions directly, need to
// store an app ID to pretend there is a context
import env from "../environment"
import Context from "./Context"
import {
baseGlobalDBName,
DocumentType,
getDB,
getDevelopmentAppID,
getProdAppID,
SEPARATOR,
} from "../db"
import { ContextMap } from "./constants"
import { Database, IdentityContext } from "@budibase/types"
import { DEFAULT_TENANT_ID } from "./index"
let TEST_APP_ID: string | null = null
export function isMultiTenant() {
return env.MULTI_TENANCY
}
export function isTenantIdSet() {
const context = Context.get()
return !!context?.tenantId
}
export function isTenancyEnabled() {
return env.MULTI_TENANCY
}
/**
* Given an app ID this will attempt to retrieve the tenant ID from it.
* @return {null|string} The tenant ID found within the app ID.
*/
export function getTenantIDFromAppID(appId: string) {
if (!appId) {
return undefined
}
if (!isMultiTenant()) {
return DEFAULT_TENANT_ID
}
const split = appId.split(SEPARATOR)
const hasDev = split[1] === DocumentType.DEV
if ((hasDev && split.length === 3) || (!hasDev && split.length === 2)) {
return undefined
}
if (hasDev) {
return split[2]
} else {
return split[1]
}
}
function updateContext(updates: ContextMap) {
let context: ContextMap
try {
context = Context.get()
} catch (err) {
// no context, start empty
context = {}
}
context = {
...context,
...updates,
}
return context
}
async function newContext(updates: ContextMap, task: any) {
// see if there already is a context setup
let context: ContextMap = updateContext(updates)
return Context.run(context, task)
}
export async function doInContext(appId: string, task: any): Promise<any> {
const tenantId = getTenantIDFromAppID(appId)
return newContext(
{
tenantId,
appId,
},
task
)
}
export async function doInTenant(
tenantId: string | null,
task: any
): Promise<any> {
// make sure default always selected in single tenancy
if (!env.MULTI_TENANCY) {
tenantId = tenantId || DEFAULT_TENANT_ID
}
const updates = tenantId ? { tenantId } : {}
return newContext(updates, task)
}
export async function doInAppContext(appId: string, task: any): Promise<any> {
if (!appId) {
throw new Error("appId is required")
}
const tenantId = getTenantIDFromAppID(appId)
const updates: ContextMap = { appId }
if (tenantId) {
updates.tenantId = tenantId
}
return newContext(updates, task)
}
export async function doInIdentityContext(
identity: IdentityContext,
task: any
): Promise<any> {
if (!identity) {
throw new Error("identity is required")
}
const context: ContextMap = {
identity,
}
if (identity.tenantId) {
context.tenantId = identity.tenantId
}
return newContext(context, task)
}
export function getIdentity(): IdentityContext | undefined {
try {
const context = Context.get()
return context?.identity
} catch (e) {
// do nothing - identity is not in context
}
}
export function getTenantId(): string {
if (!isMultiTenant()) {
return DEFAULT_TENANT_ID
}
const context = Context.get()
const tenantId = context?.tenantId
if (!tenantId) {
throw new Error("Tenant id not found")
}
return tenantId
}
export function getAppId(): string | undefined {
const context = Context.get()
const foundId = context?.appId
if (!foundId && env.isTest() && TEST_APP_ID) {
return TEST_APP_ID
} else {
return foundId
}
}
export function updateTenantId(tenantId?: string) {
let context: ContextMap = updateContext({
tenantId,
})
Context.set(context)
}
export function updateAppId(appId: string) {
let context: ContextMap = updateContext({
appId,
})
try {
Context.set(context)
} catch (err) {
if (env.isTest()) {
TEST_APP_ID = appId
} else {
throw err
}
}
}
export function getGlobalDB(): Database {
const context = Context.get()
if (!context || (env.MULTI_TENANCY && !context.tenantId)) {
throw new Error("Global DB not found")
}
return getDB(baseGlobalDBName(context?.tenantId))
}
/**
* Gets the app database based on whatever the request
* contained, dev or prod.
*/
export function getAppDB(opts?: any): Database {
const appId = getAppId()
return getDB(appId, opts)
}
/**
* This specifically gets the prod app ID, if the request
* contained a development app ID, this will get the prod one.
*/
export function getProdAppDB(opts?: any): Database {
const appId = getAppId()
if (!appId) {
throw new Error("Unable to retrieve prod DB - no app ID.")
}
return getDB(getProdAppID(appId), opts)
}
/**
* This specifically gets the dev app ID, if the request
* contained a prod app ID, this will get the dev one.
*/
export function getDevAppDB(opts?: any): Database {
const appId = getAppId()
if (!appId) {
throw new Error("Unable to retrieve dev DB - no app ID.")
}
return getDB(getDevelopmentAppID(appId), opts)
}

View File

@ -19,7 +19,7 @@ export async function created(
const properties: AutomationCreatedEvent = {
appId: automation.appId,
automationId: automation._id as string,
triggerId: automation.definition?.trigger?.id,
triggerId: automation.definition?.trigger?.id!,
triggerType: automation.definition?.trigger?.stepId,
}
await publishEvent(Event.AUTOMATION_CREATED, properties, timestamp)
@ -29,7 +29,7 @@ export async function triggerUpdated(automation: Automation) {
const properties: AutomationTriggerUpdatedEvent = {
appId: automation.appId,
automationId: automation._id as string,
triggerId: automation.definition?.trigger?.id,
triggerId: automation.definition?.trigger?.id!,
triggerType: automation.definition?.trigger?.stepId,
}
await publishEvent(Event.AUTOMATION_TRIGGER_UPDATED, properties)
@ -39,7 +39,7 @@ export async function deleted(automation: Automation) {
const properties: AutomationDeletedEvent = {
appId: automation.appId,
automationId: automation._id as string,
triggerId: automation.definition?.trigger?.id,
triggerId: automation.definition?.trigger?.id!,
triggerType: automation.definition?.trigger?.stepId,
}
await publishEvent(Event.AUTOMATION_DELETED, properties)
@ -49,7 +49,7 @@ export async function tested(automation: Automation) {
const properties: AutomationTestedEvent = {
appId: automation.appId,
automationId: automation._id as string,
triggerId: automation.definition?.trigger?.id,
triggerId: automation.definition?.trigger?.id!,
triggerType: automation.definition?.trigger?.stepId,
}
await publishEvent(Event.AUTOMATION_TESTED, properties)
@ -70,9 +70,9 @@ export async function stepCreated(
const properties: AutomationStepCreatedEvent = {
appId: automation.appId,
automationId: automation._id as string,
triggerId: automation.definition?.trigger?.id,
triggerId: automation.definition?.trigger?.id!,
triggerType: automation.definition?.trigger?.stepId,
stepId: step.id,
stepId: step.id!,
stepType: step.stepId,
}
await publishEvent(Event.AUTOMATION_STEP_CREATED, properties, timestamp)
@ -85,9 +85,9 @@ export async function stepDeleted(
const properties: AutomationStepDeletedEvent = {
appId: automation.appId,
automationId: automation._id as string,
triggerId: automation.definition?.trigger?.id,
triggerId: automation.definition?.trigger?.id!,
triggerType: automation.definition?.trigger?.stepId,
stepId: step.id,
stepId: step.id!,
stepType: step.stepId,
}
await publishEvent(Event.AUTOMATION_STEP_DELETED, properties)

View File

@ -1,6 +1,6 @@
import { BBContext } from "@budibase/types"
export = async (ctx: BBContext, next: any) => {
export = async (ctx: BBContext | any, next: any) => {
// Placeholder for audit log middleware
return next()
}

View File

@ -8,6 +8,7 @@ import { getGlobalDB, doInTenant } from "../tenancy"
import { decrypt } from "../security/encryption"
import * as identity from "../context/identity"
import env from "../environment"
import { BBContext, EndpointMatcher } from "@budibase/types"
const ONE_MINUTE = env.SESSION_UPDATE_PERIOD
? parseInt(env.SESSION_UPDATE_PERIOD)
@ -65,14 +66,14 @@ async function checkApiKey(apiKey: string, populateUser?: Function) {
* The tenancy modules should not be used here and it should be assumed that the tenancy context
* has not yet been populated.
*/
export = (
noAuthPatterns = [],
export = function (
noAuthPatterns: EndpointMatcher[] = [],
opts: { publicAllowed: boolean; populateUser?: Function } = {
publicAllowed: false,
}
) => {
) {
const noAuthOptions = noAuthPatterns ? buildMatcherRegex(noAuthPatterns) : []
return async (ctx: any, next: any) => {
return async (ctx: BBContext | any, next: any) => {
let publicEndpoint = false
const version = ctx.request.headers[Header.API_VER]
// the path is not authenticated

View File

@ -1,6 +1,6 @@
import { Header } from "../constants"
import { buildMatcherRegex, matches } from "./matchers"
import { BBContext } from "@budibase/types"
import { BBContext, EndpointMatcher } from "@budibase/types"
/**
* GET, HEAD and OPTIONS methods are considered safe operations
@ -32,9 +32,11 @@ const INCLUDED_CONTENT_TYPES = [
* https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html#synchronizer-token-pattern
*
*/
export = (opts = { noCsrfPatterns: [] }) => {
export = function (
opts: { noCsrfPatterns: EndpointMatcher[] } = { noCsrfPatterns: [] }
) {
const noCsrfOptions = buildMatcherRegex(opts.noCsrfPatterns)
return async (ctx: BBContext, next: any) => {
return async (ctx: BBContext | any, next: any) => {
// don't apply for excluded paths
const found = matches(ctx, noCsrfOptions)
if (found) {

View File

@ -1,7 +1,10 @@
import Joi, { ObjectSchema } from "joi"
import { BBContext } from "@budibase/types"
function validate(schema: Joi.ObjectSchema, property: string) {
function validate(
schema: Joi.ObjectSchema | Joi.ArraySchema,
property: string
) {
// Return a Koa middleware function
return (ctx: BBContext, next: any) => {
if (!schema) {
@ -17,8 +20,8 @@ function validate(schema: Joi.ObjectSchema, property: string) {
}
// not all schemas have the append property e.g. array schemas
if (schema.append) {
schema = schema.append({
if ((schema as Joi.ObjectSchema).append) {
schema = (schema as Joi.ObjectSchema).append({
createdAt: Joi.any().optional(),
updatedAt: Joi.any().optional(),
})
@ -33,10 +36,10 @@ function validate(schema: Joi.ObjectSchema, property: string) {
}
}
export function body(schema: Joi.ObjectSchema) {
export function body(schema: Joi.ObjectSchema | Joi.ArraySchema) {
return validate(schema, "body")
}
export function params(schema: Joi.ObjectSchema) {
export function params(schema: Joi.ObjectSchema | Joi.ArraySchema) {
return validate(schema, "params")
}

View File

@ -8,6 +8,7 @@ import {
Database,
SSOProfile,
ThirdPartyUser,
OIDCConfiguration,
} from "@budibase/types"
const OIDCStrategy = require("@techpass/passport-openidconnect").Strategy
@ -103,7 +104,10 @@ function validEmail(value: string) {
* from couchDB rather than environment variables, using this factory is necessary for dynamically configuring passport.
* @returns Dynamically configured Passport OIDC Strategy
*/
export async function strategyFactory(config: Config, saveUserFn?: Function) {
export async function strategyFactory(
config: OIDCConfiguration,
saveUserFn?: Function
) {
try {
const verify = buildVerifyFn(saveUserFn)
const strategy = new OIDCStrategy(config, verify)
@ -118,7 +122,7 @@ export async function strategyFactory(config: Config, saveUserFn?: Function) {
export async function fetchStrategyConfig(
enrichedConfig: OIDCInnerCfg,
callbackUrl?: string
) {
): Promise<OIDCConfiguration> {
try {
const { clientID, clientSecret, configUrl } = enrichedConfig

View File

@ -20,8 +20,8 @@ export function authError(done: Function, message: string, err?: any) {
export async function ssoCallbackUrl(
db: Database,
config: { callbackURL?: string },
type: ConfigType
config?: { callbackURL?: string },
type?: ConfigType
) {
// incase there is a callback URL from before
if (config && config.callbackURL) {

View File

@ -8,15 +8,15 @@ import {
TenantResolutionStrategy,
} from "@budibase/types"
const tenancy = (
export = function (
allowQueryStringPatterns: EndpointMatcher[],
noTenancyPatterns: EndpointMatcher[],
opts = { noTenancyRequired: false }
) => {
opts: { noTenancyRequired?: boolean } = { noTenancyRequired: false }
) {
const allowQsOptions = buildMatcherRegex(allowQueryStringPatterns)
const noTenancyOptions = buildMatcherRegex(noTenancyPatterns)
return async function (ctx: BBContext, next: any) {
return async function (ctx: BBContext | any, next: any) {
const allowNoTenant =
opts.noTenancyRequired || !!matches(ctx, noTenancyOptions)
const tenantOpts: GetTenantIdOptions = {
@ -33,5 +33,3 @@ const tenancy = (
return doInTenant(tenantId, next)
}
}
export = tenancy

View File

@ -3,7 +3,6 @@
"target": "es6",
"module": "commonjs",
"lib": ["es2020"],
"allowJs": true,
"strict": true,
"noImplicitAny": true,
"esModuleInterop": true,

View File

@ -31,6 +31,16 @@ export interface GoogleConfig extends Config {
}
}
export interface OIDCConfiguration {
issuer: string
authorizationURL: string
tokenURL: string
userInfoURL: string
clientID: string
clientSecret: string
callbackURL: string
}
export interface OIDCInnerCfg {
configUrl: string
clientID: string

View File

@ -3,7 +3,6 @@
"target": "es6",
"module": "commonjs",
"lib": ["es2020"],
"allowJs": true,
"strict": true,
"noImplicitAny": true,
"esModuleInterop": true,

View File

@ -1,26 +1,30 @@
import { utils, constants, auth, db as dbCore } from "@budibase/backend-core"
import {
events,
users as usersCore,
auth,
constants,
context,
db as dbCore,
events,
tenancy,
users as usersCore,
utils,
} from "@budibase/backend-core"
import { EmailTemplatePurpose } from "../../../constants"
import { sendEmail, isEmailConfigured } from "../../../utilities/email"
import { isEmailConfigured, sendEmail } from "../../../utilities/email"
import { checkResetPasswordCode } from "../../../utilities/redis"
import env from "../../../environment"
import sdk from "../../../sdk"
import { User, Config, ConfigType } from "@budibase/types"
import { Config, ConfigType, User } from "@budibase/types"
const { setCookie, getCookie, clearCookie, hash, platformLogout } = utils
const { Cookie, Header } = constants
const { passport, ssoCallbackUrl, google, oidc } = auth
export async function googleCallbackUrl(config?: Config) {
return ssoCallbackUrl(tenancy.getGlobalDB(), config, "google")
export async function googleCallbackUrl(config?: { callbackURL?: string }) {
return ssoCallbackUrl(tenancy.getGlobalDB(), config, ConfigType.GOOGLE)
}
export async function oidcCallbackUrl(config?: Config) {
return ssoCallbackUrl(tenancy.getGlobalDB(), config, "oidc")
export async function oidcCallbackUrl(config?: { callbackURL?: string }) {
return ssoCallbackUrl(tenancy.getGlobalDB(), config, ConfigType.OIDC)
}
async function authInternal(ctx: any, user: any, err = null, info = null) {

View File

@ -371,7 +371,7 @@ export async function destroy(ctx: BBContext) {
const { id, rev } = ctx.params
try {
await db.remove(id, rev)
await cache.delete(cache.CacheKey.CHECKLIST)
await cache.destroy(cache.CacheKey.CHECKLIST)
ctx.body = { message: "Config deleted successfully" }
} catch (err: any) {
ctx.throw(err.status, err)

View File

@ -85,7 +85,7 @@ if (!environment.APPS_URL) {
}
// clean up any environment variable edge cases
for (let [key, value] of Object.entries(env)) {
for (let [key, value] of Object.entries(environment)) {
// handle the edge case of "0" to disable an environment variable
if (value === "0") {
// @ts-ignore

View File

@ -3,7 +3,6 @@
"target": "es6",
"module": "commonjs",
"lib": ["es2020"],
"allowJs": true,
"strict": true,
"noImplicitAny": true,
"esModuleInterop": true,