Merge remote-tracking branch 'origin/master' into feature/multistep-form-block
This commit is contained in:
commit
c358344611
|
@ -38,10 +38,10 @@ jobs:
|
||||||
submodules: ${{ env.IS_OSS_CONTRIBUTOR == 'false' }}
|
submodules: ${{ env.IS_OSS_CONTRIBUTOR == 'false' }}
|
||||||
token: ${{ secrets.PERSONAL_ACCESS_TOKEN || github.token }}
|
token: ${{ secrets.PERSONAL_ACCESS_TOKEN || github.token }}
|
||||||
|
|
||||||
- name: Use Node.js 18.x
|
- name: Use Node.js 20.x
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: 18.x
|
node-version: 20.x
|
||||||
cache: yarn
|
cache: yarn
|
||||||
- run: yarn --frozen-lockfile
|
- run: yarn --frozen-lockfile
|
||||||
- run: yarn lint
|
- run: yarn lint
|
||||||
|
@ -56,10 +56,10 @@ jobs:
|
||||||
token: ${{ secrets.PERSONAL_ACCESS_TOKEN || github.token }}
|
token: ${{ secrets.PERSONAL_ACCESS_TOKEN || github.token }}
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Use Node.js 18.x
|
- name: Use Node.js 20.x
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: 18.x
|
node-version: 20.x
|
||||||
cache: yarn
|
cache: yarn
|
||||||
- run: yarn --frozen-lockfile
|
- run: yarn --frozen-lockfile
|
||||||
|
|
||||||
|
@ -84,7 +84,7 @@ jobs:
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Use Node.js 18.x
|
- name: Use Node.js 20.x
|
||||||
uses: azure/setup-helm@v3
|
uses: azure/setup-helm@v3
|
||||||
- run: cd charts/budibase && helm lint .
|
- run: cd charts/budibase && helm lint .
|
||||||
|
|
||||||
|
@ -98,10 +98,10 @@ jobs:
|
||||||
token: ${{ secrets.PERSONAL_ACCESS_TOKEN || github.token }}
|
token: ${{ secrets.PERSONAL_ACCESS_TOKEN || github.token }}
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Use Node.js 18.x
|
- name: Use Node.js 20.x
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: 18.x
|
node-version: 20.x
|
||||||
cache: yarn
|
cache: yarn
|
||||||
- run: yarn --frozen-lockfile
|
- run: yarn --frozen-lockfile
|
||||||
- name: Test
|
- name: Test
|
||||||
|
@ -122,10 +122,10 @@ jobs:
|
||||||
token: ${{ secrets.PERSONAL_ACCESS_TOKEN || github.token }}
|
token: ${{ secrets.PERSONAL_ACCESS_TOKEN || github.token }}
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Use Node.js 18.x
|
- name: Use Node.js 20.x
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: 18.x
|
node-version: 20.x
|
||||||
cache: yarn
|
cache: yarn
|
||||||
- run: yarn --frozen-lockfile
|
- run: yarn --frozen-lockfile
|
||||||
- name: Test worker
|
- name: Test worker
|
||||||
|
@ -146,10 +146,10 @@ jobs:
|
||||||
token: ${{ secrets.PERSONAL_ACCESS_TOKEN || github.token }}
|
token: ${{ secrets.PERSONAL_ACCESS_TOKEN || github.token }}
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Use Node.js 18.x
|
- name: Use Node.js 20.x
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: 18.x
|
node-version: 20.x
|
||||||
cache: yarn
|
cache: yarn
|
||||||
- run: yarn --frozen-lockfile
|
- run: yarn --frozen-lockfile
|
||||||
- name: Test server
|
- name: Test server
|
||||||
|
@ -171,10 +171,10 @@ jobs:
|
||||||
token: ${{ secrets.PERSONAL_ACCESS_TOKEN || github.token }}
|
token: ${{ secrets.PERSONAL_ACCESS_TOKEN || github.token }}
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Use Node.js 18.x
|
- name: Use Node.js 20.x
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: 18.x
|
node-version: 20.x
|
||||||
cache: yarn
|
cache: yarn
|
||||||
- run: yarn --frozen-lockfile
|
- run: yarn --frozen-lockfile
|
||||||
- name: Test
|
- name: Test
|
||||||
|
@ -194,10 +194,10 @@ jobs:
|
||||||
submodules: ${{ env.IS_OSS_CONTRIBUTOR == 'false' }}
|
submodules: ${{ env.IS_OSS_CONTRIBUTOR == 'false' }}
|
||||||
token: ${{ secrets.PERSONAL_ACCESS_TOKEN || github.token }}
|
token: ${{ secrets.PERSONAL_ACCESS_TOKEN || github.token }}
|
||||||
|
|
||||||
- name: Use Node.js 18.x
|
- name: Use Node.js 20.x
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: 18.x
|
node-version: 20.x
|
||||||
cache: yarn
|
cache: yarn
|
||||||
- run: yarn --frozen-lockfile
|
- run: yarn --frozen-lockfile
|
||||||
- name: Build packages
|
- name: Build packages
|
||||||
|
|
|
@ -16,8 +16,8 @@ jobs:
|
||||||
days-before-pr-stale: 7
|
days-before-pr-stale: 7
|
||||||
stale-issue-label: stale
|
stale-issue-label: stale
|
||||||
exempt-pr-labels: pinned,security,roadmap
|
exempt-pr-labels: pinned,security,roadmap
|
||||||
|
|
||||||
days-before-pr-close: 7
|
days-before-pr-close: 7
|
||||||
|
days-before-issue-close: 30
|
||||||
|
|
||||||
- uses: actions/stale@v8
|
- uses: actions/stale@v8
|
||||||
with:
|
with:
|
||||||
|
@ -26,6 +26,7 @@ jobs:
|
||||||
days-before-stale: 30
|
days-before-stale: 30
|
||||||
only-issue-labels: bug,High priority
|
only-issue-labels: bug,High priority
|
||||||
stale-issue-label: warn
|
stale-issue-label: warn
|
||||||
|
days-before-close: 30
|
||||||
|
|
||||||
- uses: actions/stale@v8
|
- uses: actions/stale@v8
|
||||||
with:
|
with:
|
||||||
|
@ -34,6 +35,7 @@ jobs:
|
||||||
days-before-stale: 90
|
days-before-stale: 90
|
||||||
only-issue-labels: bug,Medium priority
|
only-issue-labels: bug,Medium priority
|
||||||
stale-issue-label: warn
|
stale-issue-label: warn
|
||||||
|
days-before-close: 30
|
||||||
|
|
||||||
- uses: actions/stale@v8
|
- uses: actions/stale@v8
|
||||||
with:
|
with:
|
||||||
|
@ -43,5 +45,4 @@ jobs:
|
||||||
stale-issue-label: stale
|
stale-issue-label: stale
|
||||||
only-issue-labels: bug
|
only-issue-labels: bug
|
||||||
stale-issue-message: "This issue has been automatically marked as stale because it has not had any activity for six months."
|
stale-issue-message: "This issue has been automatically marked as stale because it has not had any activity for six months."
|
||||||
|
|
||||||
days-before-close: 30
|
days-before-close: 30
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
nodejs 18.17.0
|
nodejs 20.10.0
|
||||||
python 3.10.0
|
python 3.10.0
|
||||||
yarn 1.22.19
|
yarn 1.22.19
|
||||||
|
|
|
@ -90,7 +90,7 @@ Component libraries are collections of components as well as the definition of t
|
||||||
|
|
||||||
#### 1. Prerequisites
|
#### 1. Prerequisites
|
||||||
|
|
||||||
- NodeJS version `18.x.x`
|
- NodeJS version `20.x.x`
|
||||||
- Python version `3.x`
|
- Python version `3.x`
|
||||||
|
|
||||||
### Using asdf (recommended)
|
### Using asdf (recommended)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
FROM node:18-slim as build
|
FROM node:20-slim as build
|
||||||
|
|
||||||
# install node-gyp dependencies
|
# install node-gyp dependencies
|
||||||
RUN apt-get update && apt-get install -y --no-install-recommends g++ make python3 jq
|
RUN apt-get update && apt-get install -y --no-install-recommends g++ make python3 jq
|
||||||
|
@ -42,7 +42,7 @@ COPY packages/string-templates packages/string-templates
|
||||||
FROM budibase/couchdb as runner
|
FROM budibase/couchdb as runner
|
||||||
ARG TARGETARCH
|
ARG TARGETARCH
|
||||||
ENV TARGETARCH $TARGETARCH
|
ENV TARGETARCH $TARGETARCH
|
||||||
ENV NODE_MAJOR 18
|
ENV NODE_MAJOR 20
|
||||||
#TARGETBUILD can be set to single (for single docker image) or aas (for azure app service)
|
#TARGETBUILD can be set to single (for single docker image) or aas (for azure app service)
|
||||||
# e.g. docker build --build-arg TARGETBUILD=aas ....
|
# e.g. docker build --build-arg TARGETBUILD=aas ....
|
||||||
ARG TARGETBUILD=single
|
ARG TARGETBUILD=single
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"version": "2.13.52",
|
"version": "2.14.0",
|
||||||
"npmClient": "yarn",
|
"npmClient": "yarn",
|
||||||
"packages": [
|
"packages": [
|
||||||
"packages/*",
|
"packages/*",
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
"@babel/eslint-parser": "^7.22.5",
|
"@babel/eslint-parser": "^7.22.5",
|
||||||
"@babel/preset-env": "^7.22.5",
|
"@babel/preset-env": "^7.22.5",
|
||||||
"@esbuild-plugins/tsconfig-paths": "^0.1.2",
|
"@esbuild-plugins/tsconfig-paths": "^0.1.2",
|
||||||
|
"@types/node": "20.10.0",
|
||||||
"@typescript-eslint/parser": "6.9.0",
|
"@typescript-eslint/parser": "6.9.0",
|
||||||
"esbuild": "^0.18.17",
|
"esbuild": "^0.18.17",
|
||||||
"esbuild-node-externals": "^1.8.0",
|
"esbuild-node-externals": "^1.8.0",
|
||||||
|
@ -99,7 +100,7 @@
|
||||||
"@budibase/types": "0.0.0"
|
"@budibase/types": "0.0.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18.0.0 <19.0.0"
|
"node": ">=20.0.0 <21.0.0"
|
||||||
},
|
},
|
||||||
"dependencies": {}
|
"dependencies": {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit c1a53bb2f4cafcb4c55ad7181146617b449907f2
|
Subproject commit b11e6b47370d9b77c63648b45929c86bfed6360c
|
|
@ -65,7 +65,6 @@
|
||||||
"@types/cookies": "0.7.8",
|
"@types/cookies": "0.7.8",
|
||||||
"@types/jest": "29.5.5",
|
"@types/jest": "29.5.5",
|
||||||
"@types/lodash": "4.14.200",
|
"@types/lodash": "4.14.200",
|
||||||
"@types/node": "18.17.0",
|
|
||||||
"@types/node-fetch": "2.6.4",
|
"@types/node-fetch": "2.6.4",
|
||||||
"@types/pouchdb": "6.4.0",
|
"@types/pouchdb": "6.4.0",
|
||||||
"@types/redlock": "4.0.3",
|
"@types/redlock": "4.0.3",
|
||||||
|
|
|
@ -134,7 +134,7 @@ export async function doInContext(appId: string, task: any): Promise<any> {
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function doInTenant<T>(
|
export async function doInTenant<T>(
|
||||||
tenantId: string | null,
|
tenantId: string | undefined,
|
||||||
task: () => T
|
task: () => T
|
||||||
): Promise<T> {
|
): Promise<T> {
|
||||||
// make sure default always selected in single tenancy
|
// make sure default always selected in single tenancy
|
||||||
|
|
|
@ -33,6 +33,7 @@ export * as docUpdates from "./docUpdates"
|
||||||
export * from "./utils/Duration"
|
export * from "./utils/Duration"
|
||||||
export { SearchParams } from "./db"
|
export { SearchParams } from "./db"
|
||||||
export * as docIds from "./docIds"
|
export * as docIds from "./docIds"
|
||||||
|
export * as security from "./security"
|
||||||
// Add context to tenancy for backwards compatibility
|
// Add context to tenancy for backwards compatibility
|
||||||
// only do this for external usages to prevent internal
|
// only do this for external usages to prevent internal
|
||||||
// circular dependencies
|
// circular dependencies
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
import { env } from ".."
|
||||||
|
|
||||||
|
export const PASSWORD_MIN_LENGTH = +(process.env.PASSWORD_MIN_LENGTH || 8)
|
||||||
|
export const PASSWORD_MAX_LENGTH = +(process.env.PASSWORD_MAX_LENGTH || 512)
|
||||||
|
|
||||||
|
export function validatePassword(
|
||||||
|
password: string
|
||||||
|
): { valid: true } | { valid: false; error: string } {
|
||||||
|
if (!password || password.length < PASSWORD_MIN_LENGTH) {
|
||||||
|
return {
|
||||||
|
valid: false,
|
||||||
|
error: `Password invalid. Minimum ${PASSWORD_MIN_LENGTH} characters.`,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (password.length > PASSWORD_MAX_LENGTH) {
|
||||||
|
return {
|
||||||
|
valid: false,
|
||||||
|
error: `Password invalid. Maximum ${PASSWORD_MAX_LENGTH} characters.`,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { valid: true }
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
export * from "./auth"
|
|
@ -0,0 +1,45 @@
|
||||||
|
import { generator } from "../../../tests"
|
||||||
|
import { PASSWORD_MAX_LENGTH, validatePassword } from "../auth"
|
||||||
|
|
||||||
|
describe("auth", () => {
|
||||||
|
describe("validatePassword", () => {
|
||||||
|
it("a valid password returns successful", () => {
|
||||||
|
expect(validatePassword("password")).toEqual({ valid: true })
|
||||||
|
})
|
||||||
|
|
||||||
|
it.each([
|
||||||
|
["undefined", undefined],
|
||||||
|
["null", null],
|
||||||
|
["empty", ""],
|
||||||
|
])("%s returns unsuccessful", (_, password) => {
|
||||||
|
expect(validatePassword(password as string)).toEqual({
|
||||||
|
valid: false,
|
||||||
|
error: "Password invalid. Minimum 8 characters.",
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it.each([
|
||||||
|
generator.word({ length: PASSWORD_MAX_LENGTH }),
|
||||||
|
generator.paragraph().substring(0, PASSWORD_MAX_LENGTH),
|
||||||
|
])(`can use passwords up to 512 characters in length`, password => {
|
||||||
|
expect(validatePassword(password)).toEqual({
|
||||||
|
valid: true,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it.each([
|
||||||
|
generator.word({ length: PASSWORD_MAX_LENGTH + 1 }),
|
||||||
|
generator
|
||||||
|
.paragraph({ sentences: 50 })
|
||||||
|
.substring(0, PASSWORD_MAX_LENGTH + 1),
|
||||||
|
])(
|
||||||
|
`passwords cannot have more than ${PASSWORD_MAX_LENGTH} characters`,
|
||||||
|
password => {
|
||||||
|
expect(validatePassword(password)).toEqual({
|
||||||
|
valid: false,
|
||||||
|
error: "Password invalid. Maximum 512 characters.",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
|
@ -39,7 +39,7 @@ const ALL_STRATEGIES = Object.values(TenantResolutionStrategy)
|
||||||
export const getTenantIDFromCtx = (
|
export const getTenantIDFromCtx = (
|
||||||
ctx: BBContext,
|
ctx: BBContext,
|
||||||
opts: GetTenantIdOptions
|
opts: GetTenantIdOptions
|
||||||
): string | null => {
|
): string | undefined => {
|
||||||
// exit early if not multi-tenant
|
// exit early if not multi-tenant
|
||||||
if (!isMultiTenant()) {
|
if (!isMultiTenant()) {
|
||||||
return DEFAULT_TENANT_ID
|
return DEFAULT_TENANT_ID
|
||||||
|
@ -144,5 +144,5 @@ export const getTenantIDFromCtx = (
|
||||||
ctx.throw(403, "Tenant id not set")
|
ctx.throw(403, "Tenant id not set")
|
||||||
}
|
}
|
||||||
|
|
||||||
return null
|
return undefined
|
||||||
}
|
}
|
||||||
|
|
|
@ -157,12 +157,12 @@ describe("getTenantIDFromCtx", () => {
|
||||||
TenantResolutionStrategy.PATH,
|
TenantResolutionStrategy.PATH,
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
expect(getTenantIDFromCtx(ctx, mockOpts)).toBeNull()
|
expect(getTenantIDFromCtx(ctx, mockOpts)).toBeUndefined()
|
||||||
expect(ctx.throw).toBeCalledTimes(1)
|
expect(ctx.throw).toBeCalledTimes(1)
|
||||||
expect(ctx.throw).toBeCalledWith(403, "Tenant id not set")
|
expect(ctx.throw).toBeCalledWith(403, "Tenant id not set")
|
||||||
})
|
})
|
||||||
|
|
||||||
it("returns null if allowNoTenant is true", () => {
|
it("returns undefined if allowNoTenant is true", () => {
|
||||||
const ctx = createCtx({})
|
const ctx = createCtx({})
|
||||||
mockOpts = {
|
mockOpts = {
|
||||||
allowNoTenant: true,
|
allowNoTenant: true,
|
||||||
|
@ -172,7 +172,7 @@ describe("getTenantIDFromCtx", () => {
|
||||||
TenantResolutionStrategy.PATH,
|
TenantResolutionStrategy.PATH,
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
expect(getTenantIDFromCtx(ctx, mockOpts)).toBeNull()
|
expect(getTenantIDFromCtx(ctx, mockOpts)).toBeUndefined()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,7 @@ import {
|
||||||
} from "./utils"
|
} from "./utils"
|
||||||
import { searchExistingEmails } from "./lookup"
|
import { searchExistingEmails } from "./lookup"
|
||||||
import { hash } from "../utils"
|
import { hash } from "../utils"
|
||||||
|
import { validatePassword } from "../security"
|
||||||
|
|
||||||
type QuotaUpdateFn = (
|
type QuotaUpdateFn = (
|
||||||
change: number,
|
change: number,
|
||||||
|
@ -110,6 +111,12 @@ export class UserDB {
|
||||||
if (await UserDB.isPreventPasswordActions(user, account)) {
|
if (await UserDB.isPreventPasswordActions(user, account)) {
|
||||||
throw new HTTPError("Password change is disabled for this user", 400)
|
throw new HTTPError("Password change is disabled for this user", 400)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const passwordValidation = validatePassword(password)
|
||||||
|
if (!passwordValidation.valid) {
|
||||||
|
throw new HTTPError(passwordValidation.error, 400)
|
||||||
|
}
|
||||||
|
|
||||||
hashedPassword = opts.hashPassword ? await hash(password) : password
|
hashedPassword = opts.hashPassword ? await hash(password) : password
|
||||||
} else if (dbUser) {
|
} else if (dbUser) {
|
||||||
hashedPassword = dbUser.password
|
hashedPassword = dbUser.password
|
||||||
|
|
|
@ -31,8 +31,8 @@ export async function resolveAppUrl(ctx: Ctx) {
|
||||||
const appUrl = ctx.path.split("/")[2]
|
const appUrl = ctx.path.split("/")[2]
|
||||||
let possibleAppUrl = `/${appUrl.toLowerCase()}`
|
let possibleAppUrl = `/${appUrl.toLowerCase()}`
|
||||||
|
|
||||||
let tenantId: string | null = context.getTenantId()
|
let tenantId: string | undefined = context.getTenantId()
|
||||||
if (env.MULTI_TENANCY) {
|
if (!env.isDev() && env.MULTI_TENANCY) {
|
||||||
// always use the tenant id from the subdomain in multi tenancy
|
// always use the tenant id from the subdomain in multi tenancy
|
||||||
// this ensures the logged-in user tenant id doesn't overwrite
|
// this ensures the logged-in user tenant id doesn't overwrite
|
||||||
// e.g. in the case of viewing a public app while already logged-in to another tenant
|
// e.g. in the case of viewing a public app while already logged-in to another tenant
|
||||||
|
@ -41,7 +41,7 @@ export async function resolveAppUrl(ctx: Ctx) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// search prod apps for a url that matches
|
// search prod apps for an url that matches
|
||||||
const apps: App[] = await context.doInTenant(
|
const apps: App[] = await context.doInTenant(
|
||||||
tenantId,
|
tenantId,
|
||||||
() => getAllApps({ dev: false }) as Promise<App[]>
|
() => getAllApps({ dev: false }) as Promise<App[]>
|
||||||
|
|
|
@ -21,7 +21,7 @@ export const user = (userProps?: Partial<Omit<User, "userId">>): User => {
|
||||||
_id: userId,
|
_id: userId,
|
||||||
userId,
|
userId,
|
||||||
email: newEmail(),
|
email: newEmail(),
|
||||||
password: "test",
|
password: "password",
|
||||||
roles: { app_test: "admin" },
|
roles: { app_test: "admin" },
|
||||||
firstName: generator.first(),
|
firstName: generator.first(),
|
||||||
lastName: generator.last(),
|
lastName: generator.last(),
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { string, number } from "yup"
|
import { string, number, object } from "yup"
|
||||||
|
|
||||||
const propertyValidator = type => {
|
const propertyValidator = type => {
|
||||||
if (type === "number") {
|
if (type === "number") {
|
||||||
|
@ -9,6 +9,10 @@ const propertyValidator = type => {
|
||||||
return string().email().nullable()
|
return string().email().nullable()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (type === "object") {
|
||||||
|
return object().nullable()
|
||||||
|
}
|
||||||
|
|
||||||
return string().nullable()
|
return string().nullable()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,7 +41,7 @@
|
||||||
<div class="filter-editor">
|
<div class="filter-editor">
|
||||||
<ActionButton on:click={drawer.show}>{text}</ActionButton>
|
<ActionButton on:click={drawer.show}>{text}</ActionButton>
|
||||||
</div>
|
</div>
|
||||||
<Drawer bind:this={drawer} title="Filtering">
|
<Drawer bind:this={drawer} title="Filtering" on:drawerHide on:drawerShow>
|
||||||
<Button cta slot="buttons" on:click={saveFilter}>Save</Button>
|
<Button cta slot="buttons" on:click={saveFilter}>Save</Button>
|
||||||
<FilterDrawer
|
<FilterDrawer
|
||||||
slot="body"
|
slot="body"
|
||||||
|
|
|
@ -32,4 +32,4 @@
|
||||||
$: schema = linkedTable?.schema
|
$: schema = linkedTable?.schema
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<FilterEditor on:change {...$$props} {schema} />
|
<FilterEditor on:change {...$$props} {schema} on:drawerHide on:drawerShow />
|
||||||
|
|
|
@ -38,7 +38,7 @@
|
||||||
$goto("../portal")
|
$goto("../portal")
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
submitted = false
|
submitted = false
|
||||||
notifications.error("Failed to create admin user")
|
notifications.error(error.message || "Failed to create admin user")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -45,7 +45,7 @@
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
submitted = false
|
submitted = false
|
||||||
notifications.error("Unable to reset password")
|
notifications.error(err.message || "Unable to reset password")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,6 @@ build/
|
||||||
docker-error.log
|
docker-error.log
|
||||||
envoy.yaml
|
envoy.yaml
|
||||||
*.tar.gz
|
*.tar.gz
|
||||||
prebuilds/
|
|
||||||
dist/
|
dist/
|
||||||
budibase-automation/
|
budibase-automation/
|
||||||
budibase-component/
|
budibase-component/
|
||||||
|
|
|
@ -9,26 +9,11 @@
|
||||||
"author": "Budibase",
|
"author": "Budibase",
|
||||||
"license": "GPL-3.0",
|
"license": "GPL-3.0",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"prebuild": "rm -rf prebuilds 2> /dev/null && cp -r ../../node_modules/leveldown/prebuilds prebuilds",
|
|
||||||
"rename": "renamer --find .node --replace .fake 'prebuilds/**'",
|
|
||||||
"tsc": "node ../../scripts/build.js",
|
"tsc": "node ../../scripts/build.js",
|
||||||
"pkg": "pkg . --out-path build --no-bytecode --public --public-packages \"*\" -C GZip",
|
"build": "yarn tsc",
|
||||||
"build": "yarn prebuild && yarn rename && yarn tsc && yarn pkg && yarn postbuild",
|
|
||||||
"check:types": "tsc -p tsconfig.json --noEmit --paths null",
|
"check:types": "tsc -p tsconfig.json --noEmit --paths null",
|
||||||
"postbuild": "rm -rf prebuilds 2> /dev/null",
|
|
||||||
"start": "ts-node ./src/index.ts"
|
"start": "ts-node ./src/index.ts"
|
||||||
},
|
},
|
||||||
"pkg": {
|
|
||||||
"targets": [
|
|
||||||
"node18-linux",
|
|
||||||
"node18-win",
|
|
||||||
"node18-macos"
|
|
||||||
],
|
|
||||||
"assets": [
|
|
||||||
"prebuilds/**/*"
|
|
||||||
],
|
|
||||||
"outputPath": "build"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@budibase/backend-core": "0.0.0",
|
"@budibase/backend-core": "0.0.0",
|
||||||
"@budibase/string-templates": "0.0.0",
|
"@budibase/string-templates": "0.0.0",
|
||||||
|
@ -43,7 +28,6 @@
|
||||||
"inquirer": "8.0.0",
|
"inquirer": "8.0.0",
|
||||||
"lookpath": "1.1.0",
|
"lookpath": "1.1.0",
|
||||||
"node-fetch": "2.6.7",
|
"node-fetch": "2.6.7",
|
||||||
"pkg": "5.8.0",
|
|
||||||
"posthog-node": "1.3.0",
|
"posthog-node": "1.3.0",
|
||||||
"pouchdb": "7.3.0",
|
"pouchdb": "7.3.0",
|
||||||
"pouchdb-replication-stream": "1.2.9",
|
"pouchdb-replication-stream": "1.2.9",
|
||||||
|
@ -55,7 +39,6 @@
|
||||||
"@types/jest": "29.5.5",
|
"@types/jest": "29.5.5",
|
||||||
"@types/node-fetch": "2.6.4",
|
"@types/node-fetch": "2.6.4",
|
||||||
"@types/pouchdb": "^6.4.0",
|
"@types/pouchdb": "^6.4.0",
|
||||||
"renamer": "^4.0.0",
|
|
||||||
"ts-node": "10.8.1",
|
"ts-node": "10.8.1",
|
||||||
"typescript": "5.2.2"
|
"typescript": "5.2.2"
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
process.env.DISABLE_PINO_LOGGER = "1"
|
process.env.DISABLE_PINO_LOGGER = "1"
|
||||||
import "./prebuilds"
|
|
||||||
import "./environment"
|
import "./environment"
|
||||||
import { getCommands } from "./options"
|
import { getCommands } from "./options"
|
||||||
import { Command } from "commander"
|
import { Command } from "commander"
|
||||||
import { getHelpDescription } from "./utils"
|
import { getHelpDescription, error } from "./utils"
|
||||||
import { version } from "../package.json"
|
import { version } from "../package.json"
|
||||||
|
|
||||||
// add hosting config
|
// add hosting config
|
||||||
|
@ -21,6 +20,23 @@ async function init() {
|
||||||
await program.parseAsync(process.argv)
|
await program.parseAsync(process.argv)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const events = ["exit", "SIGINT", "SIGUSR1", "SIGUSR2", "uncaughtException"]
|
||||||
|
events.forEach(event => {
|
||||||
|
process.on(event, (evt?: number) => {
|
||||||
|
if (evt && !isNaN(evt)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (evt) {
|
||||||
|
console.error(
|
||||||
|
error(
|
||||||
|
"Failed to run CLI command - please report with the following message:"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
console.error(error(evt))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
init().catch(err => {
|
init().catch(err => {
|
||||||
console.error(`Unexpected error - `, err)
|
console.error(`Unexpected error - `, err)
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,57 +0,0 @@
|
||||||
import os from "os"
|
|
||||||
import { join } from "path"
|
|
||||||
import fs from "fs"
|
|
||||||
import { error } from "./utils"
|
|
||||||
|
|
||||||
const PREBUILDS = "prebuilds"
|
|
||||||
const ARCH = `${os.platform()}-${os.arch()}`
|
|
||||||
const PREBUILD_DIR = join(process.execPath, "..", "cli", PREBUILDS, ARCH)
|
|
||||||
|
|
||||||
// running as built CLI pkg bundle
|
|
||||||
if (!process.argv[0].includes("node")) {
|
|
||||||
checkForBinaries()
|
|
||||||
}
|
|
||||||
|
|
||||||
function localPrebuildPath() {
|
|
||||||
return join(process.execPath, "..", PREBUILDS)
|
|
||||||
}
|
|
||||||
|
|
||||||
function checkForBinaries() {
|
|
||||||
const readDir = join(__filename, "..", "..", "..", "cli", PREBUILDS, ARCH)
|
|
||||||
if (fs.existsSync(PREBUILD_DIR) || !fs.existsSync(readDir)) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const natives = fs.readdirSync(readDir)
|
|
||||||
if (fs.existsSync(readDir)) {
|
|
||||||
const writePath = join(localPrebuildPath(), ARCH)
|
|
||||||
fs.mkdirSync(writePath, { recursive: true })
|
|
||||||
for (let native of natives) {
|
|
||||||
const filename = `${native.split(".fake")[0]}.node`
|
|
||||||
fs.cpSync(join(readDir, native), join(writePath, filename))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function cleanup(evt?: number) {
|
|
||||||
// cleanup prebuilds first
|
|
||||||
const path = localPrebuildPath()
|
|
||||||
if (fs.existsSync(path)) {
|
|
||||||
fs.rmSync(path, { recursive: true })
|
|
||||||
}
|
|
||||||
if (evt && !isNaN(evt)) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (evt) {
|
|
||||||
console.error(
|
|
||||||
error(
|
|
||||||
"Failed to run CLI command - please report with the following message:"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
console.error(error(evt))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const events = ["exit", "SIGINT", "SIGUSR1", "SIGUSR2", "uncaughtException"]
|
|
||||||
events.forEach(event => {
|
|
||||||
process.on(event, cleanup)
|
|
||||||
})
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 992486c10044a7495496b97bdf5f454d4020bfba
|
Subproject commit dc2b1b22e7f9bac705746bf1fb72c817db043fa3
|
|
@ -1,4 +1,4 @@
|
||||||
FROM node:18-slim
|
FROM node:20-slim
|
||||||
|
|
||||||
LABEL com.centurylinklabs.watchtower.lifecycle.pre-check="scripts/watchtower-hooks/pre-check.sh"
|
LABEL com.centurylinklabs.watchtower.lifecycle.pre-check="scripts/watchtower-hooks/pre-check.sh"
|
||||||
LABEL com.centurylinklabs.watchtower.lifecycle.pre-update="scripts/watchtower-hooks/pre-update.sh"
|
LABEL com.centurylinklabs.watchtower.lifecycle.pre-update="scripts/watchtower-hooks/pre-update.sh"
|
||||||
|
|
|
@ -86,7 +86,7 @@
|
||||||
"lodash": "4.17.21",
|
"lodash": "4.17.21",
|
||||||
"memorystream": "0.3.1",
|
"memorystream": "0.3.1",
|
||||||
"mongodb": "5.7",
|
"mongodb": "5.7",
|
||||||
"mssql": "9.1.1",
|
"mssql": "10.0.1",
|
||||||
"mysql2": "3.5.2",
|
"mysql2": "3.5.2",
|
||||||
"node-fetch": "2.6.7",
|
"node-fetch": "2.6.7",
|
||||||
"object-sizeof": "2.6.1",
|
"object-sizeof": "2.6.1",
|
||||||
|
@ -121,8 +121,7 @@
|
||||||
"@types/koa": "2.13.4",
|
"@types/koa": "2.13.4",
|
||||||
"@types/koa__router": "8.0.8",
|
"@types/koa__router": "8.0.8",
|
||||||
"@types/lodash": "4.14.200",
|
"@types/lodash": "4.14.200",
|
||||||
"@types/mssql": "8.1.2",
|
"@types/mssql": "9.1.4",
|
||||||
"@types/node": "18.17.0",
|
|
||||||
"@types/node-fetch": "2.6.4",
|
"@types/node-fetch": "2.6.4",
|
||||||
"@types/oracledb": "5.2.2",
|
"@types/oracledb": "5.2.2",
|
||||||
"@types/pg": "8.6.6",
|
"@types/pg": "8.6.6",
|
||||||
|
|
|
@ -48,6 +48,7 @@ async function init() {
|
||||||
HTTP_MIGRATIONS: "0",
|
HTTP_MIGRATIONS: "0",
|
||||||
HTTP_LOGGING: "0",
|
HTTP_LOGGING: "0",
|
||||||
VERSION: "0.0.0+local",
|
VERSION: "0.0.0+local",
|
||||||
|
PASSWORD_MIN_LENGTH: "1",
|
||||||
}
|
}
|
||||||
|
|
||||||
config = { ...config, ...existingConfig }
|
config = { ...config, ...existingConfig }
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@budibase/nano": "10.1.4",
|
"@budibase/nano": "10.1.4",
|
||||||
"@types/koa": "2.13.4",
|
"@types/koa": "2.13.4",
|
||||||
"@types/node": "18.17.0",
|
|
||||||
"@types/pouchdb": "6.4.0",
|
"@types/pouchdb": "6.4.0",
|
||||||
"@types/redlock": "4.0.3",
|
"@types/redlock": "4.0.3",
|
||||||
"rimraf": "3.0.2",
|
"rimraf": "3.0.2",
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
FROM node:18-alpine
|
FROM node:20-alpine
|
||||||
|
|
||||||
LABEL com.centurylinklabs.watchtower.lifecycle.pre-check="scripts/watchtower-hooks/pre-check.sh"
|
LABEL com.centurylinklabs.watchtower.lifecycle.pre-check="scripts/watchtower-hooks/pre-check.sh"
|
||||||
LABEL com.centurylinklabs.watchtower.lifecycle.pre-update="scripts/watchtower-hooks/pre-update.sh"
|
LABEL com.centurylinklabs.watchtower.lifecycle.pre-update="scripts/watchtower-hooks/pre-update.sh"
|
||||||
|
|
|
@ -79,7 +79,6 @@
|
||||||
"@types/koa": "2.13.4",
|
"@types/koa": "2.13.4",
|
||||||
"@types/koa__router": "8.0.8",
|
"@types/koa__router": "8.0.8",
|
||||||
"@types/lodash": "4.14.200",
|
"@types/lodash": "4.14.200",
|
||||||
"@types/node": "18.17.0",
|
|
||||||
"@types/node-fetch": "2.6.4",
|
"@types/node-fetch": "2.6.4",
|
||||||
"@types/server-destroy": "1.0.1",
|
"@types/server-destroy": "1.0.1",
|
||||||
"@types/supertest": "2.0.14",
|
"@types/supertest": "2.0.14",
|
||||||
|
|
|
@ -30,6 +30,7 @@ async function init() {
|
||||||
ENABLE_EMAIL_TEST_MODE: "1",
|
ENABLE_EMAIL_TEST_MODE: "1",
|
||||||
HTTP_LOGGING: "0",
|
HTTP_LOGGING: "0",
|
||||||
VERSION: "0.0.0+local",
|
VERSION: "0.0.0+local",
|
||||||
|
PASSWORD_MIN_LENGTH: "1",
|
||||||
}
|
}
|
||||||
|
|
||||||
config = { ...config, ...existingConfig }
|
config = { ...config, ...existingConfig }
|
||||||
|
|
|
@ -122,10 +122,10 @@ export const resetUpdate = async (ctx: Ctx<PasswordResetUpdateRequest>) => {
|
||||||
ctx.body = {
|
ctx.body = {
|
||||||
message: "password reset successfully.",
|
message: "password reset successfully.",
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
console.warn(err)
|
console.warn(err)
|
||||||
// hide any details of the error for security
|
// hide any details of the error for security
|
||||||
ctx.throw(400, "Cannot reset password.")
|
ctx.throw(400, err.message || "Cannot reset password.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -229,7 +229,7 @@ describe("/api/global/auth", () => {
|
||||||
)
|
)
|
||||||
|
|
||||||
expect(res.body).toEqual({
|
expect(res.body).toEqual({
|
||||||
message: "Cannot reset password.",
|
message: "Password change is disabled for this user",
|
||||||
status: 400,
|
status: 400,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -261,8 +261,12 @@ describe("/api/global/auth", () => {
|
||||||
)
|
)
|
||||||
|
|
||||||
// convert to account owner now that password has been requested
|
// convert to account owner now that password has been requested
|
||||||
const account = structures.accounts.ssoAccount() as CloudAccount
|
const account: CloudAccount = {
|
||||||
mocks.accounts.getAccount.mockReturnValueOnce(
|
...structures.accounts.ssoAccount(),
|
||||||
|
budibaseUserId: "budibaseUserId",
|
||||||
|
email: user.email,
|
||||||
|
}
|
||||||
|
mocks.accounts.getAccountByTenantId.mockReturnValueOnce(
|
||||||
Promise.resolve(account)
|
Promise.resolve(account)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,7 @@ class TestConfiguration {
|
||||||
tenantId: string
|
tenantId: string
|
||||||
user?: User
|
user?: User
|
||||||
apiKey?: string
|
apiKey?: string
|
||||||
userPassword = "test"
|
userPassword = "password"
|
||||||
|
|
||||||
constructor(opts: { openServer: boolean } = { openServer: true }) {
|
constructor(opts: { openServer: boolean } = { openServer: true }) {
|
||||||
// default to cloud hosting
|
// default to cloud hosting
|
||||||
|
|
|
@ -101,7 +101,7 @@ export class UserAPI extends TestAPI {
|
||||||
if (!request) {
|
if (!request) {
|
||||||
request = {
|
request = {
|
||||||
email: structures.email(),
|
email: structures.email(),
|
||||||
password: generator.string(),
|
password: generator.string({ length: 8 }),
|
||||||
tenantId: structures.tenant.id(),
|
tenantId: structures.tenant.id(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue