mirror of
https://github.com/dbeaver/cloudbeaver.git
synced 2026-10-16 14:50:15 +08:00
Compare commits
37
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6b8425ecf9 | ||
|
|
00b214b8bc | ||
|
|
ea6c960353 | ||
|
|
44c0cfe856 | ||
|
|
a4c1c6e174 | ||
|
|
470d64718b | ||
|
|
0c0669f0c7 | ||
|
|
2a012d600c | ||
|
|
0b2370d414 | ||
|
|
a0def9f3ae | ||
|
|
13cf2911e0 | ||
|
|
c0c3594633 | ||
|
|
180ec65dd9 | ||
|
|
79d5702744 | ||
|
|
603b94c551 | ||
|
|
ad6973d069 | ||
|
|
231da5b0b8 | ||
|
|
57e77b7cd1 | ||
|
|
58c4744aa7 | ||
|
|
39c7346e0a | ||
|
|
131b1e13f4 | ||
|
|
3914461f55 | ||
|
|
5dc6e5ca38 | ||
|
|
c747c30063 | ||
|
|
ad225404f4 | ||
|
|
d9fe873bb5 | ||
|
|
0193e67f72 | ||
|
|
8ebf7eba9c | ||
|
|
848b95113a | ||
|
|
d4c304f725 | ||
|
|
444ff0d672 | ||
|
|
bf49a94642 | ||
|
|
3a2e41fa69 | ||
|
|
36e8d1fac9 | ||
|
|
dcc13811e8 | ||
|
|
2ba910386f | ||
|
|
a7c5d53f0a |
@@ -85,8 +85,8 @@ jobs:
|
||||
- run: yarn test
|
||||
working-directory: ./cloudbeaver/common-typescript
|
||||
|
||||
# - run: yarn test
|
||||
# working-directory: ./cloudbeaver/common-react
|
||||
- run: yarn test
|
||||
working-directory: ./cloudbeaver/common-react
|
||||
|
||||
- run: yarn test
|
||||
|
||||
|
||||
Vendored
+29
@@ -19,6 +19,26 @@
|
||||
"group": "test",
|
||||
"args": ["test"]
|
||||
},
|
||||
{
|
||||
"label": "Run Tests Common Typescript",
|
||||
"type": "shell",
|
||||
"command": "yarn",
|
||||
"group": "test",
|
||||
"args": ["test"],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/common-typescript"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "Run Tests Common React",
|
||||
"type": "shell",
|
||||
"command": "yarn",
|
||||
"group": "test",
|
||||
"args": ["test"],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/common-react"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "Run DevServer CE",
|
||||
"group": "build",
|
||||
@@ -107,6 +127,15 @@
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/webapp/packages"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "Run Ui Kit Preview",
|
||||
"type": "shell",
|
||||
"command": "yarn",
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/common-react/@dbeaver/ui-kit"
|
||||
},
|
||||
"args": ["docs"]
|
||||
}
|
||||
],
|
||||
"inputs": [
|
||||
|
||||
@@ -25,6 +25,18 @@ You can see a live demo of CloudBeaver here: https://demo.cloudbeaver.io
|
||||
|
||||
## Changelog
|
||||
|
||||
### 25.1.4 2025-08-04
|
||||
- Added an ability to review the script before execution when users edit tables without primary keys in the Data Editor;
|
||||
- DuckDB: driver has been updated to version 1.3.2;
|
||||
- Databend: driver has been updated to version 0.3.9.
|
||||
|
||||
### 25.1.3 2025-07-21
|
||||
- A password confirmation field has been added for administrators in the Easy Config section to help prevent accidental misconfigurations;
|
||||
- Added column descriptions in the Data Editor to provide more metadata context. You can disable this in Preferences > Data Viewer;
|
||||
- Added the option to display tabs across multiple rows, allowing you to see all tabs without scrolling. You can enable this in Preferences > Interface;
|
||||
- Changed the default engine used for autocompletion in the SQL Editor. This Semantic engine offers improved suggestions for database objects, keywords, and functions. You can switch back to the Legacy engine in Preferences -> SQL Editor;
|
||||
- Clickhouse: fixed the presentation of tuples and map data types in the data editor.
|
||||
|
||||
### 25.1.2 2025-07-07
|
||||
- The CloudBeaver default theme matches the device theme by default now. You can change this behavior in user preferences under the Theme section;
|
||||
- Added a button “Clear” to the Output panel;
|
||||
|
||||
@@ -28,7 +28,8 @@
|
||||
"@dbeaver/tsconfig": "workspace:^",
|
||||
"@types/react": "^19",
|
||||
"rimraf": "^6",
|
||||
"typescript": "^5"
|
||||
"typescript": "^5",
|
||||
"vitest": "^3"
|
||||
},
|
||||
"dependencies": {
|
||||
"react": "^19"
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import React from 'react';
|
||||
import { DND_STORE_PREFIX, DnDStore, getStoreProvider } from './store.js';
|
||||
|
||||
function createMockDragEvent(id?: string): React.DragEvent<HTMLElement> {
|
||||
const types = id ? [DND_STORE_PREFIX + id] : [];
|
||||
return {
|
||||
dataTransfer: { types },
|
||||
} as unknown as React.DragEvent<HTMLElement>;
|
||||
}
|
||||
|
||||
describe('DnDStore', () => {
|
||||
it('sets and gets data correctly', () => {
|
||||
const store = new DnDStore();
|
||||
store.setData('id1', 'key1', 'value1');
|
||||
expect(store.getData('id1', 'key1')).toBe('value1');
|
||||
});
|
||||
|
||||
it('removes data correctly', () => {
|
||||
const store = new DnDStore();
|
||||
|
||||
store.setData('id2', 'key2', 'value2');
|
||||
store.removeData('id2');
|
||||
expect(store.getData('id2', 'key2')).toBeUndefined();
|
||||
});
|
||||
|
||||
it('getProvider returns a working provider', () => {
|
||||
const store = new DnDStore();
|
||||
|
||||
const provider = store.getProvider('id3');
|
||||
provider.setData('key3', 'value3');
|
||||
expect(provider.getData('key3')).toBe('value3');
|
||||
provider.removeData();
|
||||
expect(provider.getData('key3')).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('getStoreProvider', () => {
|
||||
it('returns null if no DND_STORE_PREFIX type is present', () => {
|
||||
const event = createMockDragEvent();
|
||||
expect(getStoreProvider(event)).toBeNull();
|
||||
});
|
||||
|
||||
it('returns a provider if DND_STORE_PREFIX type is present', () => {
|
||||
const id = 'testid';
|
||||
const event = createMockDragEvent(id);
|
||||
const provider = getStoreProvider(event);
|
||||
expect(provider).not.toBeNull();
|
||||
provider!.setData('foo', 'bar');
|
||||
expect(provider!.getData('foo')).toBe('bar');
|
||||
provider!.removeData();
|
||||
expect(provider!.getData('foo')).toBeUndefined();
|
||||
});
|
||||
});
|
||||
@@ -6,7 +6,7 @@ export interface DnDStoreProvider {
|
||||
removeData: () => void;
|
||||
}
|
||||
|
||||
class DnDStore {
|
||||
export class DnDStore {
|
||||
private data: Map<string, Record<string, any>> = new Map();
|
||||
setData(id: string, key: string, value: any) {
|
||||
if (!this.data.has(id)) {
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
# @dbeaver/react-tests
|
||||
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"name": "@dbeaver/react-tests",
|
||||
"type": "module",
|
||||
"sideEffects": [],
|
||||
"exports": {
|
||||
".": "./lib/index.js",
|
||||
"./*": "./lib/*.js"
|
||||
},
|
||||
"scripts": {
|
||||
"clear": "rimraf lib"
|
||||
},
|
||||
"files": [
|
||||
"package.json",
|
||||
"LICENSE",
|
||||
"README.md",
|
||||
"CHANGELOG.md",
|
||||
"lib",
|
||||
"!lib/**/*.d.ts.map",
|
||||
"!lib/**/*.test.js",
|
||||
"!lib/**/*.test.d.ts",
|
||||
"!lib/**/*.test.d.ts.map",
|
||||
"!lib/**/*.test.js.map",
|
||||
"!lib/tests",
|
||||
"!.tsbuildinfo"
|
||||
],
|
||||
"packageManager": "yarn@4.9.2",
|
||||
"devDependencies": {
|
||||
"@dbeaver/cli": "workspace:^",
|
||||
"@dbeaver/tsconfig": "workspace:^",
|
||||
"@testing-library/dom": "^10",
|
||||
"@testing-library/jest-dom": "^6",
|
||||
"@testing-library/react": "^16",
|
||||
"@types/node": "^22",
|
||||
"rimraf": "^6",
|
||||
"typescript": "^5",
|
||||
"vitest": "^3"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export { default as ReactVitestConfig } from './vitest.config.js';
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* CloudBeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020-2025 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0.
|
||||
* you may not use this file except in compliance with the License.
|
||||
*/
|
||||
import { mergeConfig, defineConfig } from 'vitest/config';
|
||||
import { DefaultVitestConfig } from '@dbeaver/cli';
|
||||
import { posix } from 'node:path';
|
||||
|
||||
export default mergeConfig(
|
||||
DefaultVitestConfig,
|
||||
defineConfig({
|
||||
test: {
|
||||
environment: 'happy-dom',
|
||||
setupFiles: [posix.resolve('./vitest.setup.js')],
|
||||
alias: [
|
||||
{
|
||||
find: /.*.(css|scss|less)$/,
|
||||
replacement: import.meta.resolve('./__mocks__/styleMock.js'),
|
||||
},
|
||||
],
|
||||
css: false,
|
||||
},
|
||||
plugins: [
|
||||
{
|
||||
name: 'vitest-setup',
|
||||
resolveId(source) {
|
||||
if (source === posix.resolve('./vitest.setup.js')) {
|
||||
return '\0internal:vitest-setup';
|
||||
}
|
||||
return null;
|
||||
},
|
||||
load(id) {
|
||||
if (id === '\0internal:vitest-setup') {
|
||||
return "import '@dbeaver/react-tests/vitest.setup';";
|
||||
}
|
||||
return null;
|
||||
},
|
||||
},
|
||||
],
|
||||
}),
|
||||
);
|
||||
+1
@@ -5,6 +5,7 @@
|
||||
* Licensed under the Apache License, Version 2.0.
|
||||
* you may not use this file except in compliance with the License.
|
||||
*/
|
||||
|
||||
import '@testing-library/jest-dom/vitest';
|
||||
|
||||
// different machine has its own timezones and some tests can fail because of it
|
||||
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"extends": "@dbeaver/tsconfig/tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"tsBuildInfoFile": "./lib/.tsbuildinfo",
|
||||
"rootDir": "src",
|
||||
"rootDirs": [
|
||||
"src"
|
||||
],
|
||||
"outDir": "lib",
|
||||
"incremental": true,
|
||||
"composite": true
|
||||
},
|
||||
"include": [
|
||||
"src"
|
||||
],
|
||||
"references": [
|
||||
{
|
||||
"path": "../../../common-typescript/@dbeaver/cli"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -6,23 +6,49 @@
|
||||
* you may not use this file except in compliance with the License.
|
||||
*/
|
||||
|
||||
import { type ComponentPropsWithRef } from 'react';
|
||||
import { type ComponentPropsWithRef, type ReactElement, useId } from 'react';
|
||||
import './Input.css';
|
||||
import clsx from 'clsx';
|
||||
import { componentProviderWrapper } from '../componentProviderWrapper.js';
|
||||
|
||||
export interface InputProps extends Omit<ComponentPropsWithRef<'input'>, 'size'> {
|
||||
size?: 'small' | 'medium' | 'large' | 'xlarge';
|
||||
label?: React.ReactNode;
|
||||
}
|
||||
export type InputProps = Omit<ComponentPropsWithRef<'input'>, 'size'> & {
|
||||
label?: ReactElement | string;
|
||||
size?: 'small' | 'medium' | 'large' | 'xlarge';
|
||||
};
|
||||
|
||||
export const InputBase: React.FC<InputProps> = function Input({ size, className, ...props }) {
|
||||
export const InputBase: React.FC<InputProps> = function Input({
|
||||
size,
|
||||
className,
|
||||
label,
|
||||
'aria-labelledby': ariaLabelledBy,
|
||||
'aria-label': ariaLabel,
|
||||
...props
|
||||
}) {
|
||||
const labelId = useId();
|
||||
const classNameToApply = clsx(`dbv-kit-input`, `dbv-kit-input--${size ?? 'medium'}`, className);
|
||||
|
||||
if (label) {
|
||||
return (
|
||||
<label className="dbv-kit-input-wrapper">
|
||||
<div id={labelId} className={clsx('dbv-kit-input__title', props.required && 'dbv-kit-input__title--required')}>
|
||||
{label}
|
||||
</div>
|
||||
<input
|
||||
className={classNameToApply}
|
||||
aria-labelledby={labelId}
|
||||
{...props}
|
||||
/>
|
||||
</label>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<label className="dbv-kit-input-wrapper">
|
||||
{props.label && <div className={clsx('dbv-kit-input__title', props.required && 'dbv-kit-input__title--required')}>{props.label}</div>}
|
||||
<input className={classNameToApply} {...props} />
|
||||
</label>
|
||||
<input
|
||||
className={classNameToApply}
|
||||
aria-labelledby={ariaLabelledBy}
|
||||
aria-label={ariaLabel}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -20,19 +20,20 @@
|
||||
font-weight: var(--dbv-kit-select-font-weight);
|
||||
font-size: var(--dbv-kit-select-font-size);
|
||||
outline-width: var(--dbv-kit-control-outline-width);
|
||||
outline-offset: var(--dbv-kit-control-outline-offset);
|
||||
outline-color: var(--dbv-kit-control-outline-color);
|
||||
|
||||
&:hover {
|
||||
border-color: var(--dbv-kit-color-control-hover);
|
||||
&:hover:not(:disabled) {
|
||||
border-color: var(--dbv-kit-select-hover-border-color);
|
||||
}
|
||||
|
||||
&[aria-disabled='true'] {
|
||||
opacity: var(--dbv-kit-control-disabled-opacity);
|
||||
color: var(--dbv-kit-select-disabled-foreground);
|
||||
background-color: var(--dbv-kit-select-disabled-background);
|
||||
}
|
||||
&[data-focus-visible],
|
||||
&:focus-visible {
|
||||
outline-style: solid;
|
||||
outline-offset: var(--dbv-kit-control-outline-offset);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,6 +75,8 @@
|
||||
.dbv-kit-select__item {
|
||||
display: block;
|
||||
width: 100%;
|
||||
font-weight: var(--dbv-kit-select-font-weight);
|
||||
font-size: var(--dbv-kit-select-font-size);
|
||||
padding-inline: var(--dbv-kit-select-item-padding-inline);
|
||||
padding-block: var(--dbv-kit-select-item-padding-block);
|
||||
text-align: left;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
import { useState } from 'react';
|
||||
import clsx from 'clsx';
|
||||
import { SelectProvider, Select, SelectPopover, SelectItem, SelectLabel } from './Select.js';
|
||||
import { SelectProvider, Select, SelectPopover, SelectItem, SelectLabel, type SelectProviderProps } from './Select.js';
|
||||
import './SelectField.css';
|
||||
|
||||
export interface SelectItem<T> {
|
||||
@@ -57,6 +57,8 @@ export interface SelectFieldProps<T, ItemType = SelectItem<T>> {
|
||||
|
||||
className?: string;
|
||||
|
||||
noItemsPlaceholder?: React.ReactNode;
|
||||
|
||||
/**
|
||||
* Custom renderer for the selected value, overrides itemRenderer for the selected state
|
||||
* Only needed for special formatting of the selected value different from list items
|
||||
@@ -67,6 +69,16 @@ export interface SelectFieldProps<T, ItemType = SelectItem<T>> {
|
||||
* Custom arrow icon React Node that will be rendered instead default one
|
||||
*/
|
||||
arrowIcon?: React.ReactNode;
|
||||
|
||||
store?: SelectProviderProps['store'];
|
||||
|
||||
autoFocusItemsOnShow?: boolean;
|
||||
|
||||
'aria-labelledby'?: string,
|
||||
|
||||
'aria-label'?: string
|
||||
|
||||
id?: string;
|
||||
}
|
||||
|
||||
// Utility function to get value by it's key or using getter function
|
||||
@@ -82,13 +94,17 @@ export function SelectField<T, ItemType extends {} = SelectItem<T>>({
|
||||
itemRender,
|
||||
itemDisabled,
|
||||
label,
|
||||
noItemsPlaceholder = 'No items',
|
||||
description,
|
||||
disabled,
|
||||
required,
|
||||
className,
|
||||
selectedRender,
|
||||
arrowIcon,
|
||||
store,
|
||||
autoFocusItemsOnShow,
|
||||
name,
|
||||
id,
|
||||
}: SelectFieldProps<T, ItemType>) {
|
||||
const getItemValue = (item: ItemType): T =>
|
||||
getValueByPath<ItemType, T>(item, itemValue, i => ('value' in i ? (i as unknown as SelectItem<T>).value : (i as unknown as T)));
|
||||
@@ -115,29 +131,28 @@ export function SelectField<T, ItemType extends {} = SelectItem<T>>({
|
||||
|
||||
const selectedItem = items.find(item => getItemValue(item) === currentValue);
|
||||
|
||||
const displayValue = selectedItem ? (selectedRender ? selectedRender(currentValue, selectedItem) : renderItem(selectedItem)) : '';
|
||||
const displayValue = selectedRender ? selectedRender(currentValue, selectedItem) : selectedItem ? renderItem(selectedItem) : '';
|
||||
|
||||
return (
|
||||
<div className={clsx('dbv-kit-select-field', className)}>
|
||||
<SelectProvider value={currentValue as any} setValue={val => handleChange(val as T)}>
|
||||
<SelectProvider value={currentValue as any} setValue={val => handleChange(val as T)} store={store}>
|
||||
{label && <SelectLabel className={clsx(required && 'dbv-kit-select__label--required')}>{label}</SelectLabel>}
|
||||
|
||||
<Select name={name} disabled={disabled}>
|
||||
<Select id={id} name={name} disabled={disabled} required={required}>
|
||||
{displayValue}
|
||||
{arrowIcon ?? <Select.Arrow />}
|
||||
{arrowIcon ?? <Select.Arrow className='dbv-kit-select__arrow-icon' />}
|
||||
</Select>
|
||||
{description && <span className="dbv-kit-select__description">{description}</span>}
|
||||
|
||||
<SelectPopover gutter={4} unmountOnHide>
|
||||
<SelectPopover autoFocusOnShow={autoFocusItemsOnShow} gutter={4} unmountOnHide>
|
||||
{items.length === 0 ? (
|
||||
<div className="dbv-kit-select__empty">No items</div>
|
||||
<div className="dbv-kit-select__empty">{noItemsPlaceholder}</div>
|
||||
) : (
|
||||
items.map(item => (
|
||||
<SelectItem
|
||||
key={String(getItemValue(item))}
|
||||
value={getItemValue(item) as any}
|
||||
disabled={isItemDisabled(item)}
|
||||
className="dbv-kit-select__item"
|
||||
>
|
||||
{renderItem(item)}
|
||||
</SelectItem>
|
||||
|
||||
@@ -5,11 +5,14 @@
|
||||
|
||||
--dbv-kit-select-foreground: var(--dbv-kit-color-foreground);
|
||||
--dbv-kit-select-background: var(--dbv-kit-color-background);
|
||||
--dbv-kit-select-disabled-foreground: var(--dbv-kit-control-disabled-foreground);
|
||||
--dbv-kit-select-disabled-background: var(--dbv-kit-control-disabled-background);
|
||||
|
||||
--dbv-kit-select-border-width: var(--dbv-kit-control-border-width);
|
||||
--dbv-kit-select-border-color: var(--dbv-kit-color-control-inactive);
|
||||
--dbv-kit-select-border-style: solid;
|
||||
--dbv-kit-select-border-radius: var(--dbv-kit-control-border-radius);
|
||||
--dbv-kit-select-hover-border-color: var(--dbv-kit-color-control-hover);
|
||||
|
||||
--dbv-kit-select-font-weight: var(--tw-font-weight-normal);
|
||||
--dbv-kit-select-font-size: calc(var(--dbv-kit-font-size-base) * 0.875);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"name": "common-react",
|
||||
"type": "module",
|
||||
"packageManager": "yarn@4.9.2",
|
||||
"private": true,
|
||||
"workspaces": [
|
||||
@@ -7,12 +8,17 @@
|
||||
"../common-typescript"
|
||||
],
|
||||
"scripts": {
|
||||
"clear": "rimraf -g '@dbeaver/*/{dist,lib}'"
|
||||
"clear": "rimraf -g '@dbeaver/*/{dist,lib}'",
|
||||
"test": "dbeaver-test"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@dbeaver/cli": "workspace:^",
|
||||
"@dbeaver/prettier-config": "workspace:^",
|
||||
"@dbeaver/react-tests": "workspace:^",
|
||||
"@wroud/ts-template": "^0",
|
||||
"happy-dom": "^18",
|
||||
"prettier": "^3.6.2",
|
||||
"rimraf": "^6"
|
||||
"rimraf": "^6",
|
||||
"vitest": "^3"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
* CloudBeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020-2025 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0.
|
||||
* you may not use this file except in compliance with the License.
|
||||
*/
|
||||
|
||||
import { ReactVitestConfig } from '@dbeaver/react-tests';
|
||||
|
||||
export default ReactVitestConfig;
|
||||
+583
-343
File diff suppressed because it is too large
Load Diff
@@ -27,6 +27,7 @@
|
||||
"devDependencies": {
|
||||
"@dbeaver/tsconfig": "workspace:^",
|
||||
"rimraf": "^6",
|
||||
"typescript": "^5"
|
||||
"typescript": "^5",
|
||||
"vitest": "^3"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,417 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { parseJdbcUri } from './parseJdbcUri.js';
|
||||
|
||||
describe('parseJdbcUri', () => {
|
||||
describe('invalid inputs', () => {
|
||||
it('should handle null input', () => {
|
||||
const result = parseJdbcUri(null);
|
||||
expect(result).toEqual({
|
||||
raw: '',
|
||||
subprotocol: '',
|
||||
subname: '',
|
||||
queryParams: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle undefined input', () => {
|
||||
const result = parseJdbcUri(undefined);
|
||||
expect(result).toEqual({
|
||||
raw: '',
|
||||
subprotocol: '',
|
||||
subname: '',
|
||||
queryParams: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle empty string', () => {
|
||||
const result = parseJdbcUri('');
|
||||
expect(result).toEqual({
|
||||
raw: '',
|
||||
subprotocol: '',
|
||||
subname: '',
|
||||
queryParams: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle non-string input', () => {
|
||||
const result = parseJdbcUri(123 as any);
|
||||
expect(result).toEqual({
|
||||
raw: '123',
|
||||
subprotocol: '',
|
||||
subname: '',
|
||||
queryParams: {},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('non-jdbc URLs', () => {
|
||||
it('should handle non-jdbc URLs', () => {
|
||||
const result = parseJdbcUri('https://example.com');
|
||||
expect(result).toEqual({
|
||||
raw: 'https://example.com',
|
||||
subprotocol: '',
|
||||
subname: 'https://example.com',
|
||||
queryParams: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle plain text', () => {
|
||||
const result = parseJdbcUri('just some text');
|
||||
expect(result).toEqual({
|
||||
raw: 'just some text',
|
||||
subprotocol: '',
|
||||
subname: 'just some text',
|
||||
queryParams: {},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('malformed jdbc URLs', () => {
|
||||
it('should handle jdbc: without subprotocol', () => {
|
||||
const result = parseJdbcUri('jdbc:');
|
||||
expect(result).toEqual({
|
||||
raw: 'jdbc:',
|
||||
subprotocol: '',
|
||||
subname: '',
|
||||
queryParams: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle jdbc: with only subprotocol', () => {
|
||||
const result = parseJdbcUri('jdbc:mysql');
|
||||
expect(result).toEqual({
|
||||
raw: 'jdbc:mysql',
|
||||
subprotocol: '',
|
||||
subname: 'mysql',
|
||||
queryParams: {},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('SQLite URLs', () => {
|
||||
it('should parse SQLite file path', () => {
|
||||
const result = parseJdbcUri('jdbc:sqlite:/path/to/file.db');
|
||||
expect(result).toEqual({
|
||||
raw: 'jdbc:sqlite:/path/to/file.db',
|
||||
subprotocol: 'sqlite',
|
||||
subname: '/path/to/file.db',
|
||||
database: '/path/to/file.db',
|
||||
queryParams: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should parse SQLite relative path', () => {
|
||||
const result = parseJdbcUri('jdbc:sqlite:file.db');
|
||||
expect(result).toEqual({
|
||||
raw: 'jdbc:sqlite:file.db',
|
||||
subprotocol: 'sqlite',
|
||||
subname: 'file.db',
|
||||
database: 'file.db',
|
||||
queryParams: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should parse SQLite in-memory database', () => {
|
||||
const result = parseJdbcUri('jdbc:sqlite::memory:');
|
||||
expect(result).toEqual({
|
||||
raw: 'jdbc:sqlite::memory:',
|
||||
subprotocol: 'sqlite',
|
||||
subname: ':memory:',
|
||||
database: ':memory:',
|
||||
queryParams: {},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Oracle Thin URLs', () => {
|
||||
it('should parse Oracle Thin with host, port, and SID', () => {
|
||||
const result = parseJdbcUri('jdbc:oracle:thin:@localhost:1521:XE');
|
||||
expect(result).toEqual({
|
||||
raw: 'jdbc:oracle:thin:@localhost:1521:XE',
|
||||
subprotocol: 'oracle',
|
||||
subname: 'thin:@localhost:1521:XE',
|
||||
host: 'localhost',
|
||||
port: '1521',
|
||||
database: 'XE',
|
||||
queryParams: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle malformed Oracle Thin URL', () => {
|
||||
const result = parseJdbcUri('jdbc:oracle:thin:@localhost');
|
||||
expect(result).toEqual({
|
||||
raw: 'jdbc:oracle:thin:@localhost',
|
||||
subprotocol: 'oracle',
|
||||
subname: 'thin:@localhost',
|
||||
queryParams: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle Oracle Thin with different format', () => {
|
||||
const result = parseJdbcUri('jdbc:oracle:thin:@localhost:1521');
|
||||
expect(result).toEqual({
|
||||
raw: 'jdbc:oracle:thin:@localhost:1521',
|
||||
subprotocol: 'oracle',
|
||||
subname: 'thin:@localhost:1521',
|
||||
queryParams: {},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('standard JDBC URLs with //', () => {
|
||||
it('should parse MySQL URL with host and port', () => {
|
||||
const result = parseJdbcUri('jdbc:mysql://localhost:3306/testdb');
|
||||
expect(result).toEqual({
|
||||
raw: 'jdbc:mysql://localhost:3306/testdb',
|
||||
subprotocol: 'mysql',
|
||||
subname: '//localhost:3306/testdb',
|
||||
host: 'localhost',
|
||||
port: '3306',
|
||||
database: 'testdb',
|
||||
queryParams: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should parse PostgreSQL URL without port', () => {
|
||||
const result = parseJdbcUri('jdbc:postgresql://localhost/mydb');
|
||||
expect(result).toEqual({
|
||||
raw: 'jdbc:postgresql://localhost/mydb',
|
||||
subprotocol: 'postgresql',
|
||||
subname: '//localhost/mydb',
|
||||
host: 'localhost',
|
||||
port: undefined,
|
||||
database: 'mydb',
|
||||
queryParams: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should parse URL with credentials', () => {
|
||||
const result = parseJdbcUri('jdbc:mysql://user:pass@localhost:3306/testdb');
|
||||
expect(result).toEqual({
|
||||
raw: 'jdbc:mysql://user:pass@localhost:3306/testdb',
|
||||
subprotocol: 'mysql',
|
||||
subname: '//user:pass@localhost:3306/testdb',
|
||||
host: 'localhost',
|
||||
port: '3306',
|
||||
database: 'testdb',
|
||||
username: 'user',
|
||||
password: 'pass',
|
||||
queryParams: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should parse URL with query parameters', () => {
|
||||
const result = parseJdbcUri('jdbc:mysql://localhost:3306/testdb?useSSL=false&serverTimezone=UTC');
|
||||
expect(result).toEqual({
|
||||
raw: 'jdbc:mysql://localhost:3306/testdb?useSSL=false&serverTimezone=UTC',
|
||||
subprotocol: 'mysql',
|
||||
subname: '//localhost:3306/testdb?useSSL=false&serverTimezone=UTC',
|
||||
host: 'localhost',
|
||||
port: '3306',
|
||||
database: 'testdb',
|
||||
queryParams: {
|
||||
useSSL: 'false',
|
||||
serverTimezone: 'UTC',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should parse URL with empty query parameter', () => {
|
||||
const result = parseJdbcUri('jdbc:mysql://localhost:3306/testdb?param1=¶m2=value');
|
||||
expect(result).toEqual({
|
||||
raw: 'jdbc:mysql://localhost:3306/testdb?param1=¶m2=value',
|
||||
subprotocol: 'mysql',
|
||||
subname: '//localhost:3306/testdb?param1=¶m2=value',
|
||||
host: 'localhost',
|
||||
port: '3306',
|
||||
database: 'testdb',
|
||||
queryParams: {
|
||||
param1: '',
|
||||
param2: 'value',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle URL-encoded query parameters', () => {
|
||||
const result = parseJdbcUri('jdbc:mysql://localhost:3306/testdb?param1=value%20with%20spaces¶m2=value%3Dtest');
|
||||
expect(result).toEqual({
|
||||
raw: 'jdbc:mysql://localhost:3306/testdb?param1=value%20with%20spaces¶m2=value%3Dtest',
|
||||
subprotocol: 'mysql',
|
||||
subname: '//localhost:3306/testdb?param1=value%20with%20spaces¶m2=value%3Dtest',
|
||||
host: 'localhost',
|
||||
port: '3306',
|
||||
database: 'testdb',
|
||||
queryParams: {
|
||||
param1: 'value with spaces',
|
||||
param2: 'value=test',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle malformed URL gracefully', () => {
|
||||
const result = parseJdbcUri('jdbc:mysql://:3306/testdb');
|
||||
expect(result).toEqual({
|
||||
raw: 'jdbc:mysql://:3306/testdb',
|
||||
subprotocol: 'mysql',
|
||||
subname: '//:3306/testdb',
|
||||
host: undefined,
|
||||
port: '3306',
|
||||
database: 'testdb',
|
||||
queryParams: {},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('template placeholders', () => {
|
||||
it('should handle host placeholder', () => {
|
||||
const result = parseJdbcUri('jdbc:mysql://{host}:3306/testdb');
|
||||
expect(result).toEqual({
|
||||
raw: 'jdbc:mysql://{host}:3306/testdb',
|
||||
subprotocol: 'mysql',
|
||||
subname: '//{host}:3306/testdb',
|
||||
host: undefined,
|
||||
port: '3306',
|
||||
database: '/{host}:3306/testdb',
|
||||
queryParams: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle port placeholder', () => {
|
||||
const result = parseJdbcUri('jdbc:mysql://localhost:{port}/testdb');
|
||||
expect(result).toEqual({
|
||||
raw: 'jdbc:mysql://localhost:{port}/testdb',
|
||||
subprotocol: 'mysql',
|
||||
subname: '//localhost:{port}/testdb',
|
||||
host: 'localhost',
|
||||
port: undefined,
|
||||
database: '/localhost:{port}/testdb',
|
||||
queryParams: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle database placeholder', () => {
|
||||
const result = parseJdbcUri('jdbc:mysql://localhost:3306/{database}');
|
||||
expect(result).toEqual({
|
||||
raw: 'jdbc:mysql://localhost:3306/{database}',
|
||||
subprotocol: 'mysql',
|
||||
subname: '//localhost:3306/{database}',
|
||||
host: 'localhost',
|
||||
port: '3306',
|
||||
database: '/localhost:3306/{database}',
|
||||
queryParams: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle multiple placeholders', () => {
|
||||
const result = parseJdbcUri('jdbc:mysql://{host}:{port}/{database}');
|
||||
expect(result).toEqual({
|
||||
raw: 'jdbc:mysql://{host}:{port}/{database}',
|
||||
subprotocol: 'mysql',
|
||||
subname: '//{host}:{port}/{database}',
|
||||
host: undefined,
|
||||
port: undefined,
|
||||
database: '/{host}:{port}/{database}',
|
||||
queryParams: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle placeholders with query parameters', () => {
|
||||
const result = parseJdbcUri('jdbc:mysql://{host}:{port}/{database}?useSSL=false');
|
||||
expect(result).toEqual({
|
||||
raw: 'jdbc:mysql://{host}:{port}/{database}?useSSL=false',
|
||||
subprotocol: 'mysql',
|
||||
subname: '//{host}:{port}/{database}?useSSL=false',
|
||||
host: undefined,
|
||||
port: undefined,
|
||||
database: '/{host}:{port}/{database}',
|
||||
queryParams: {
|
||||
useSSL: 'false',
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('other JDBC formats', () => {
|
||||
it('should handle simple subname as database', () => {
|
||||
const result = parseJdbcUri('jdbc:hsqldb:mem:testdb');
|
||||
expect(result).toEqual({
|
||||
raw: 'jdbc:hsqldb:mem:testdb',
|
||||
subprotocol: 'hsqldb',
|
||||
subname: 'mem:testdb',
|
||||
database: 'mem:testdb',
|
||||
queryParams: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle Derby embedded', () => {
|
||||
const result = parseJdbcUri('jdbc:derby:testdb;create=true');
|
||||
expect(result).toEqual({
|
||||
raw: 'jdbc:derby:testdb;create=true',
|
||||
subprotocol: 'derby',
|
||||
subname: 'testdb;create=true',
|
||||
database: 'testdb;create=true',
|
||||
queryParams: {},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('edge cases', () => {
|
||||
it('should handle URL with only host', () => {
|
||||
const result = parseJdbcUri('jdbc:mysql://localhost');
|
||||
expect(result).toEqual({
|
||||
raw: 'jdbc:mysql://localhost',
|
||||
subprotocol: 'mysql',
|
||||
subname: '//localhost',
|
||||
host: 'localhost',
|
||||
port: undefined,
|
||||
database: undefined,
|
||||
queryParams: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle URL with host and port but no database', () => {
|
||||
const result = parseJdbcUri('jdbc:mysql://localhost:3306');
|
||||
expect(result).toEqual({
|
||||
raw: 'jdbc:mysql://localhost:3306',
|
||||
subprotocol: 'mysql',
|
||||
subname: '//localhost:3306',
|
||||
host: 'localhost',
|
||||
port: '3306',
|
||||
database: undefined,
|
||||
queryParams: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle URL with empty database', () => {
|
||||
const result = parseJdbcUri('jdbc:mysql://localhost:3306/');
|
||||
expect(result).toEqual({
|
||||
raw: 'jdbc:mysql://localhost:3306/',
|
||||
subprotocol: 'mysql',
|
||||
subname: '//localhost:3306/',
|
||||
host: 'localhost',
|
||||
port: '3306',
|
||||
database: undefined,
|
||||
username: undefined,
|
||||
password: undefined,
|
||||
queryParams: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle URL with only query parameters', () => {
|
||||
const result = parseJdbcUri('jdbc:mysql://localhost:3306/?param1=value1');
|
||||
expect(result).toEqual({
|
||||
raw: 'jdbc:mysql://localhost:3306/?param1=value1',
|
||||
subprotocol: 'mysql',
|
||||
subname: '//localhost:3306/?param1=value1',
|
||||
host: 'localhost',
|
||||
port: '3306',
|
||||
database: undefined,
|
||||
username: undefined,
|
||||
password: undefined,
|
||||
queryParams: {
|
||||
param1: 'value1',
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -30,5 +30,8 @@
|
||||
"rimraf": "^6",
|
||||
"typescript": "^5",
|
||||
"vitest": "^3"
|
||||
},
|
||||
"dependencies": {
|
||||
"async-mutex": "^0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
export * from './isDefined.js';
|
||||
export * from './isNotNullDefined.js';
|
||||
export * from './mutex.js';
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
export * as mutex from 'async-mutex';
|
||||
+238
-224
@@ -95,12 +95,12 @@ __metadata:
|
||||
linkType: hard
|
||||
|
||||
"@babel/types@npm:^7.26.7, @babel/types@npm:^7.27.1, @babel/types@npm:^7.28.0":
|
||||
version: 7.28.0
|
||||
resolution: "@babel/types@npm:7.28.0"
|
||||
version: 7.28.2
|
||||
resolution: "@babel/types@npm:7.28.2"
|
||||
dependencies:
|
||||
"@babel/helper-string-parser": "npm:^7.27.1"
|
||||
"@babel/helper-validator-identifier": "npm:^7.27.1"
|
||||
checksum: 10c0/7ca8521bf5e2d2ed4db31176efaaf94463a6b7a4d16dcc60e34e963b3596c2ecadb85457bebed13a9ee9a5829ef5f515d05b55a991b6a8f3b835451843482e39
|
||||
checksum: 10c0/24b11c9368e7e2c291fe3c1bcd1ed66f6593a3975f479cbb9dd7b8c8d8eab8a962b0d2fca616c043396ce82500ac7d23d594fbbbd013828182c01596370a0b10
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -135,6 +135,7 @@ __metadata:
|
||||
"@dbeaver/tsconfig": "workspace:^"
|
||||
rimraf: "npm:^6"
|
||||
typescript: "npm:^5"
|
||||
vitest: "npm:^3"
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
@@ -144,6 +145,7 @@ __metadata:
|
||||
dependencies:
|
||||
"@dbeaver/cli": "workspace:^"
|
||||
"@dbeaver/tsconfig": "workspace:^"
|
||||
async-mutex: "npm:^0"
|
||||
rimraf: "npm:^6"
|
||||
typescript: "npm:^5"
|
||||
vitest: "npm:^3"
|
||||
@@ -182,184 +184,184 @@ __metadata:
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@esbuild/aix-ppc64@npm:0.25.6":
|
||||
version: 0.25.6
|
||||
resolution: "@esbuild/aix-ppc64@npm:0.25.6"
|
||||
"@esbuild/aix-ppc64@npm:0.25.8":
|
||||
version: 0.25.8
|
||||
resolution: "@esbuild/aix-ppc64@npm:0.25.8"
|
||||
conditions: os=aix & cpu=ppc64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/android-arm64@npm:0.25.6":
|
||||
version: 0.25.6
|
||||
resolution: "@esbuild/android-arm64@npm:0.25.6"
|
||||
"@esbuild/android-arm64@npm:0.25.8":
|
||||
version: 0.25.8
|
||||
resolution: "@esbuild/android-arm64@npm:0.25.8"
|
||||
conditions: os=android & cpu=arm64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/android-arm@npm:0.25.6":
|
||||
version: 0.25.6
|
||||
resolution: "@esbuild/android-arm@npm:0.25.6"
|
||||
"@esbuild/android-arm@npm:0.25.8":
|
||||
version: 0.25.8
|
||||
resolution: "@esbuild/android-arm@npm:0.25.8"
|
||||
conditions: os=android & cpu=arm
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/android-x64@npm:0.25.6":
|
||||
version: 0.25.6
|
||||
resolution: "@esbuild/android-x64@npm:0.25.6"
|
||||
"@esbuild/android-x64@npm:0.25.8":
|
||||
version: 0.25.8
|
||||
resolution: "@esbuild/android-x64@npm:0.25.8"
|
||||
conditions: os=android & cpu=x64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/darwin-arm64@npm:0.25.6":
|
||||
version: 0.25.6
|
||||
resolution: "@esbuild/darwin-arm64@npm:0.25.6"
|
||||
"@esbuild/darwin-arm64@npm:0.25.8":
|
||||
version: 0.25.8
|
||||
resolution: "@esbuild/darwin-arm64@npm:0.25.8"
|
||||
conditions: os=darwin & cpu=arm64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/darwin-x64@npm:0.25.6":
|
||||
version: 0.25.6
|
||||
resolution: "@esbuild/darwin-x64@npm:0.25.6"
|
||||
"@esbuild/darwin-x64@npm:0.25.8":
|
||||
version: 0.25.8
|
||||
resolution: "@esbuild/darwin-x64@npm:0.25.8"
|
||||
conditions: os=darwin & cpu=x64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/freebsd-arm64@npm:0.25.6":
|
||||
version: 0.25.6
|
||||
resolution: "@esbuild/freebsd-arm64@npm:0.25.6"
|
||||
"@esbuild/freebsd-arm64@npm:0.25.8":
|
||||
version: 0.25.8
|
||||
resolution: "@esbuild/freebsd-arm64@npm:0.25.8"
|
||||
conditions: os=freebsd & cpu=arm64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/freebsd-x64@npm:0.25.6":
|
||||
version: 0.25.6
|
||||
resolution: "@esbuild/freebsd-x64@npm:0.25.6"
|
||||
"@esbuild/freebsd-x64@npm:0.25.8":
|
||||
version: 0.25.8
|
||||
resolution: "@esbuild/freebsd-x64@npm:0.25.8"
|
||||
conditions: os=freebsd & cpu=x64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/linux-arm64@npm:0.25.6":
|
||||
version: 0.25.6
|
||||
resolution: "@esbuild/linux-arm64@npm:0.25.6"
|
||||
"@esbuild/linux-arm64@npm:0.25.8":
|
||||
version: 0.25.8
|
||||
resolution: "@esbuild/linux-arm64@npm:0.25.8"
|
||||
conditions: os=linux & cpu=arm64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/linux-arm@npm:0.25.6":
|
||||
version: 0.25.6
|
||||
resolution: "@esbuild/linux-arm@npm:0.25.6"
|
||||
"@esbuild/linux-arm@npm:0.25.8":
|
||||
version: 0.25.8
|
||||
resolution: "@esbuild/linux-arm@npm:0.25.8"
|
||||
conditions: os=linux & cpu=arm
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/linux-ia32@npm:0.25.6":
|
||||
version: 0.25.6
|
||||
resolution: "@esbuild/linux-ia32@npm:0.25.6"
|
||||
"@esbuild/linux-ia32@npm:0.25.8":
|
||||
version: 0.25.8
|
||||
resolution: "@esbuild/linux-ia32@npm:0.25.8"
|
||||
conditions: os=linux & cpu=ia32
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/linux-loong64@npm:0.25.6":
|
||||
version: 0.25.6
|
||||
resolution: "@esbuild/linux-loong64@npm:0.25.6"
|
||||
"@esbuild/linux-loong64@npm:0.25.8":
|
||||
version: 0.25.8
|
||||
resolution: "@esbuild/linux-loong64@npm:0.25.8"
|
||||
conditions: os=linux & cpu=loong64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/linux-mips64el@npm:0.25.6":
|
||||
version: 0.25.6
|
||||
resolution: "@esbuild/linux-mips64el@npm:0.25.6"
|
||||
"@esbuild/linux-mips64el@npm:0.25.8":
|
||||
version: 0.25.8
|
||||
resolution: "@esbuild/linux-mips64el@npm:0.25.8"
|
||||
conditions: os=linux & cpu=mips64el
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/linux-ppc64@npm:0.25.6":
|
||||
version: 0.25.6
|
||||
resolution: "@esbuild/linux-ppc64@npm:0.25.6"
|
||||
"@esbuild/linux-ppc64@npm:0.25.8":
|
||||
version: 0.25.8
|
||||
resolution: "@esbuild/linux-ppc64@npm:0.25.8"
|
||||
conditions: os=linux & cpu=ppc64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/linux-riscv64@npm:0.25.6":
|
||||
version: 0.25.6
|
||||
resolution: "@esbuild/linux-riscv64@npm:0.25.6"
|
||||
"@esbuild/linux-riscv64@npm:0.25.8":
|
||||
version: 0.25.8
|
||||
resolution: "@esbuild/linux-riscv64@npm:0.25.8"
|
||||
conditions: os=linux & cpu=riscv64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/linux-s390x@npm:0.25.6":
|
||||
version: 0.25.6
|
||||
resolution: "@esbuild/linux-s390x@npm:0.25.6"
|
||||
"@esbuild/linux-s390x@npm:0.25.8":
|
||||
version: 0.25.8
|
||||
resolution: "@esbuild/linux-s390x@npm:0.25.8"
|
||||
conditions: os=linux & cpu=s390x
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/linux-x64@npm:0.25.6":
|
||||
version: 0.25.6
|
||||
resolution: "@esbuild/linux-x64@npm:0.25.6"
|
||||
"@esbuild/linux-x64@npm:0.25.8":
|
||||
version: 0.25.8
|
||||
resolution: "@esbuild/linux-x64@npm:0.25.8"
|
||||
conditions: os=linux & cpu=x64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/netbsd-arm64@npm:0.25.6":
|
||||
version: 0.25.6
|
||||
resolution: "@esbuild/netbsd-arm64@npm:0.25.6"
|
||||
"@esbuild/netbsd-arm64@npm:0.25.8":
|
||||
version: 0.25.8
|
||||
resolution: "@esbuild/netbsd-arm64@npm:0.25.8"
|
||||
conditions: os=netbsd & cpu=arm64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/netbsd-x64@npm:0.25.6":
|
||||
version: 0.25.6
|
||||
resolution: "@esbuild/netbsd-x64@npm:0.25.6"
|
||||
"@esbuild/netbsd-x64@npm:0.25.8":
|
||||
version: 0.25.8
|
||||
resolution: "@esbuild/netbsd-x64@npm:0.25.8"
|
||||
conditions: os=netbsd & cpu=x64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/openbsd-arm64@npm:0.25.6":
|
||||
version: 0.25.6
|
||||
resolution: "@esbuild/openbsd-arm64@npm:0.25.6"
|
||||
"@esbuild/openbsd-arm64@npm:0.25.8":
|
||||
version: 0.25.8
|
||||
resolution: "@esbuild/openbsd-arm64@npm:0.25.8"
|
||||
conditions: os=openbsd & cpu=arm64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/openbsd-x64@npm:0.25.6":
|
||||
version: 0.25.6
|
||||
resolution: "@esbuild/openbsd-x64@npm:0.25.6"
|
||||
"@esbuild/openbsd-x64@npm:0.25.8":
|
||||
version: 0.25.8
|
||||
resolution: "@esbuild/openbsd-x64@npm:0.25.8"
|
||||
conditions: os=openbsd & cpu=x64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/openharmony-arm64@npm:0.25.6":
|
||||
version: 0.25.6
|
||||
resolution: "@esbuild/openharmony-arm64@npm:0.25.6"
|
||||
"@esbuild/openharmony-arm64@npm:0.25.8":
|
||||
version: 0.25.8
|
||||
resolution: "@esbuild/openharmony-arm64@npm:0.25.8"
|
||||
conditions: os=openharmony & cpu=arm64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/sunos-x64@npm:0.25.6":
|
||||
version: 0.25.6
|
||||
resolution: "@esbuild/sunos-x64@npm:0.25.6"
|
||||
"@esbuild/sunos-x64@npm:0.25.8":
|
||||
version: 0.25.8
|
||||
resolution: "@esbuild/sunos-x64@npm:0.25.8"
|
||||
conditions: os=sunos & cpu=x64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/win32-arm64@npm:0.25.6":
|
||||
version: 0.25.6
|
||||
resolution: "@esbuild/win32-arm64@npm:0.25.6"
|
||||
"@esbuild/win32-arm64@npm:0.25.8":
|
||||
version: 0.25.8
|
||||
resolution: "@esbuild/win32-arm64@npm:0.25.8"
|
||||
conditions: os=win32 & cpu=arm64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/win32-ia32@npm:0.25.6":
|
||||
version: 0.25.6
|
||||
resolution: "@esbuild/win32-ia32@npm:0.25.6"
|
||||
"@esbuild/win32-ia32@npm:0.25.8":
|
||||
version: 0.25.8
|
||||
resolution: "@esbuild/win32-ia32@npm:0.25.8"
|
||||
conditions: os=win32 & cpu=ia32
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/win32-x64@npm:0.25.6":
|
||||
version: 0.25.6
|
||||
resolution: "@esbuild/win32-x64@npm:0.25.6"
|
||||
"@esbuild/win32-x64@npm:0.25.8":
|
||||
version: 0.25.8
|
||||
resolution: "@esbuild/win32-x64@npm:0.25.8"
|
||||
conditions: os=win32 & cpu=x64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
@@ -610,142 +612,142 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@rollup/rollup-android-arm-eabi@npm:4.44.2":
|
||||
version: 4.44.2
|
||||
resolution: "@rollup/rollup-android-arm-eabi@npm:4.44.2"
|
||||
"@rollup/rollup-android-arm-eabi@npm:4.46.1":
|
||||
version: 4.46.1
|
||||
resolution: "@rollup/rollup-android-arm-eabi@npm:4.46.1"
|
||||
conditions: os=android & cpu=arm
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@rollup/rollup-android-arm64@npm:4.44.2":
|
||||
version: 4.44.2
|
||||
resolution: "@rollup/rollup-android-arm64@npm:4.44.2"
|
||||
"@rollup/rollup-android-arm64@npm:4.46.1":
|
||||
version: 4.46.1
|
||||
resolution: "@rollup/rollup-android-arm64@npm:4.46.1"
|
||||
conditions: os=android & cpu=arm64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@rollup/rollup-darwin-arm64@npm:4.44.2":
|
||||
version: 4.44.2
|
||||
resolution: "@rollup/rollup-darwin-arm64@npm:4.44.2"
|
||||
"@rollup/rollup-darwin-arm64@npm:4.46.1":
|
||||
version: 4.46.1
|
||||
resolution: "@rollup/rollup-darwin-arm64@npm:4.46.1"
|
||||
conditions: os=darwin & cpu=arm64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@rollup/rollup-darwin-x64@npm:4.44.2":
|
||||
version: 4.44.2
|
||||
resolution: "@rollup/rollup-darwin-x64@npm:4.44.2"
|
||||
"@rollup/rollup-darwin-x64@npm:4.46.1":
|
||||
version: 4.46.1
|
||||
resolution: "@rollup/rollup-darwin-x64@npm:4.46.1"
|
||||
conditions: os=darwin & cpu=x64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@rollup/rollup-freebsd-arm64@npm:4.44.2":
|
||||
version: 4.44.2
|
||||
resolution: "@rollup/rollup-freebsd-arm64@npm:4.44.2"
|
||||
"@rollup/rollup-freebsd-arm64@npm:4.46.1":
|
||||
version: 4.46.1
|
||||
resolution: "@rollup/rollup-freebsd-arm64@npm:4.46.1"
|
||||
conditions: os=freebsd & cpu=arm64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@rollup/rollup-freebsd-x64@npm:4.44.2":
|
||||
version: 4.44.2
|
||||
resolution: "@rollup/rollup-freebsd-x64@npm:4.44.2"
|
||||
"@rollup/rollup-freebsd-x64@npm:4.46.1":
|
||||
version: 4.46.1
|
||||
resolution: "@rollup/rollup-freebsd-x64@npm:4.46.1"
|
||||
conditions: os=freebsd & cpu=x64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@rollup/rollup-linux-arm-gnueabihf@npm:4.44.2":
|
||||
version: 4.44.2
|
||||
resolution: "@rollup/rollup-linux-arm-gnueabihf@npm:4.44.2"
|
||||
"@rollup/rollup-linux-arm-gnueabihf@npm:4.46.1":
|
||||
version: 4.46.1
|
||||
resolution: "@rollup/rollup-linux-arm-gnueabihf@npm:4.46.1"
|
||||
conditions: os=linux & cpu=arm & libc=glibc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@rollup/rollup-linux-arm-musleabihf@npm:4.44.2":
|
||||
version: 4.44.2
|
||||
resolution: "@rollup/rollup-linux-arm-musleabihf@npm:4.44.2"
|
||||
"@rollup/rollup-linux-arm-musleabihf@npm:4.46.1":
|
||||
version: 4.46.1
|
||||
resolution: "@rollup/rollup-linux-arm-musleabihf@npm:4.46.1"
|
||||
conditions: os=linux & cpu=arm & libc=musl
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@rollup/rollup-linux-arm64-gnu@npm:4.44.2":
|
||||
version: 4.44.2
|
||||
resolution: "@rollup/rollup-linux-arm64-gnu@npm:4.44.2"
|
||||
"@rollup/rollup-linux-arm64-gnu@npm:4.46.1":
|
||||
version: 4.46.1
|
||||
resolution: "@rollup/rollup-linux-arm64-gnu@npm:4.46.1"
|
||||
conditions: os=linux & cpu=arm64 & libc=glibc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@rollup/rollup-linux-arm64-musl@npm:4.44.2":
|
||||
version: 4.44.2
|
||||
resolution: "@rollup/rollup-linux-arm64-musl@npm:4.44.2"
|
||||
"@rollup/rollup-linux-arm64-musl@npm:4.46.1":
|
||||
version: 4.46.1
|
||||
resolution: "@rollup/rollup-linux-arm64-musl@npm:4.46.1"
|
||||
conditions: os=linux & cpu=arm64 & libc=musl
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@rollup/rollup-linux-loongarch64-gnu@npm:4.44.2":
|
||||
version: 4.44.2
|
||||
resolution: "@rollup/rollup-linux-loongarch64-gnu@npm:4.44.2"
|
||||
"@rollup/rollup-linux-loongarch64-gnu@npm:4.46.1":
|
||||
version: 4.46.1
|
||||
resolution: "@rollup/rollup-linux-loongarch64-gnu@npm:4.46.1"
|
||||
conditions: os=linux & cpu=loong64 & libc=glibc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@rollup/rollup-linux-powerpc64le-gnu@npm:4.44.2":
|
||||
version: 4.44.2
|
||||
resolution: "@rollup/rollup-linux-powerpc64le-gnu@npm:4.44.2"
|
||||
"@rollup/rollup-linux-ppc64-gnu@npm:4.46.1":
|
||||
version: 4.46.1
|
||||
resolution: "@rollup/rollup-linux-ppc64-gnu@npm:4.46.1"
|
||||
conditions: os=linux & cpu=ppc64 & libc=glibc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@rollup/rollup-linux-riscv64-gnu@npm:4.44.2":
|
||||
version: 4.44.2
|
||||
resolution: "@rollup/rollup-linux-riscv64-gnu@npm:4.44.2"
|
||||
"@rollup/rollup-linux-riscv64-gnu@npm:4.46.1":
|
||||
version: 4.46.1
|
||||
resolution: "@rollup/rollup-linux-riscv64-gnu@npm:4.46.1"
|
||||
conditions: os=linux & cpu=riscv64 & libc=glibc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@rollup/rollup-linux-riscv64-musl@npm:4.44.2":
|
||||
version: 4.44.2
|
||||
resolution: "@rollup/rollup-linux-riscv64-musl@npm:4.44.2"
|
||||
"@rollup/rollup-linux-riscv64-musl@npm:4.46.1":
|
||||
version: 4.46.1
|
||||
resolution: "@rollup/rollup-linux-riscv64-musl@npm:4.46.1"
|
||||
conditions: os=linux & cpu=riscv64 & libc=musl
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@rollup/rollup-linux-s390x-gnu@npm:4.44.2":
|
||||
version: 4.44.2
|
||||
resolution: "@rollup/rollup-linux-s390x-gnu@npm:4.44.2"
|
||||
"@rollup/rollup-linux-s390x-gnu@npm:4.46.1":
|
||||
version: 4.46.1
|
||||
resolution: "@rollup/rollup-linux-s390x-gnu@npm:4.46.1"
|
||||
conditions: os=linux & cpu=s390x & libc=glibc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@rollup/rollup-linux-x64-gnu@npm:4.44.2":
|
||||
version: 4.44.2
|
||||
resolution: "@rollup/rollup-linux-x64-gnu@npm:4.44.2"
|
||||
"@rollup/rollup-linux-x64-gnu@npm:4.46.1":
|
||||
version: 4.46.1
|
||||
resolution: "@rollup/rollup-linux-x64-gnu@npm:4.46.1"
|
||||
conditions: os=linux & cpu=x64 & libc=glibc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@rollup/rollup-linux-x64-musl@npm:4.44.2":
|
||||
version: 4.44.2
|
||||
resolution: "@rollup/rollup-linux-x64-musl@npm:4.44.2"
|
||||
"@rollup/rollup-linux-x64-musl@npm:4.46.1":
|
||||
version: 4.46.1
|
||||
resolution: "@rollup/rollup-linux-x64-musl@npm:4.46.1"
|
||||
conditions: os=linux & cpu=x64 & libc=musl
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@rollup/rollup-win32-arm64-msvc@npm:4.44.2":
|
||||
version: 4.44.2
|
||||
resolution: "@rollup/rollup-win32-arm64-msvc@npm:4.44.2"
|
||||
"@rollup/rollup-win32-arm64-msvc@npm:4.46.1":
|
||||
version: 4.46.1
|
||||
resolution: "@rollup/rollup-win32-arm64-msvc@npm:4.46.1"
|
||||
conditions: os=win32 & cpu=arm64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@rollup/rollup-win32-ia32-msvc@npm:4.44.2":
|
||||
version: 4.44.2
|
||||
resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.44.2"
|
||||
"@rollup/rollup-win32-ia32-msvc@npm:4.46.1":
|
||||
version: 4.46.1
|
||||
resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.46.1"
|
||||
conditions: os=win32 & cpu=ia32
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@rollup/rollup-win32-x64-msvc@npm:4.44.2":
|
||||
version: 4.44.2
|
||||
resolution: "@rollup/rollup-win32-x64-msvc@npm:4.44.2"
|
||||
"@rollup/rollup-win32-x64-msvc@npm:4.46.1":
|
||||
version: 4.46.1
|
||||
resolution: "@rollup/rollup-win32-x64-msvc@npm:4.46.1"
|
||||
conditions: os=win32 & cpu=x64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
@@ -814,11 +816,11 @@ __metadata:
|
||||
linkType: hard
|
||||
|
||||
"@types/node@npm:^22":
|
||||
version: 22.16.0
|
||||
resolution: "@types/node@npm:22.16.0"
|
||||
version: 22.16.5
|
||||
resolution: "@types/node@npm:22.16.5"
|
||||
dependencies:
|
||||
undici-types: "npm:~6.21.0"
|
||||
checksum: 10c0/6219b521062f6c38d4d85ebd25807bd7f2bc703a5acba24e2c6716938d9d6cefd6fafd7b5156f61580eb58a0d82e8921751b778655675389631d813e5f261c03
|
||||
checksum: 10c0/93a245e96a01f4a6aa38475000070292a9299e17b95bc1fc8180c652fb3a62f9b3b9ec0b78f9fc6a78b9274d3dfce456e80c7bb68b5357c8f7dbf581df4408c1
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -989,6 +991,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"async-mutex@npm:^0":
|
||||
version: 0.5.0
|
||||
resolution: "async-mutex@npm:0.5.0"
|
||||
dependencies:
|
||||
tslib: "npm:^2.4.0"
|
||||
checksum: 10c0/9096e6ad6b674c894d8ddd5aa4c512b09bb05931b8746ebd634952b05685608b2b0820ed5c406e6569919ff5fe237ab3c491e6f2887d6da6b6ba906db3ee9c32
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"balanced-match@npm:^1.0.0":
|
||||
version: 1.0.2
|
||||
resolution: "balanced-match@npm:1.0.2"
|
||||
@@ -1052,15 +1063,15 @@ __metadata:
|
||||
linkType: hard
|
||||
|
||||
"chai@npm:^5.2.0":
|
||||
version: 5.2.0
|
||||
resolution: "chai@npm:5.2.0"
|
||||
version: 5.2.1
|
||||
resolution: "chai@npm:5.2.1"
|
||||
dependencies:
|
||||
assertion-error: "npm:^2.0.1"
|
||||
check-error: "npm:^2.1.1"
|
||||
deep-eql: "npm:^5.0.1"
|
||||
loupe: "npm:^3.1.0"
|
||||
pathval: "npm:^2.0.0"
|
||||
checksum: 10c0/dfd1cb719c7cebb051b727672d382a35338af1470065cb12adb01f4ee451bbf528e0e0f9ab2016af5fc1eea4df6e7f4504dc8443f8f00bd8fb87ad32dc516f7d
|
||||
checksum: 10c0/58209c03ae9b2fd97cfa1cb0fbe372b1906e6091311b9ba1b0468cc4923b0766a50a1050a164df3ccefb9464944c9216b632f1477c9e429068013bdbb57220f6
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -1260,35 +1271,35 @@ __metadata:
|
||||
linkType: hard
|
||||
|
||||
"esbuild@npm:^0.25.0":
|
||||
version: 0.25.6
|
||||
resolution: "esbuild@npm:0.25.6"
|
||||
version: 0.25.8
|
||||
resolution: "esbuild@npm:0.25.8"
|
||||
dependencies:
|
||||
"@esbuild/aix-ppc64": "npm:0.25.6"
|
||||
"@esbuild/android-arm": "npm:0.25.6"
|
||||
"@esbuild/android-arm64": "npm:0.25.6"
|
||||
"@esbuild/android-x64": "npm:0.25.6"
|
||||
"@esbuild/darwin-arm64": "npm:0.25.6"
|
||||
"@esbuild/darwin-x64": "npm:0.25.6"
|
||||
"@esbuild/freebsd-arm64": "npm:0.25.6"
|
||||
"@esbuild/freebsd-x64": "npm:0.25.6"
|
||||
"@esbuild/linux-arm": "npm:0.25.6"
|
||||
"@esbuild/linux-arm64": "npm:0.25.6"
|
||||
"@esbuild/linux-ia32": "npm:0.25.6"
|
||||
"@esbuild/linux-loong64": "npm:0.25.6"
|
||||
"@esbuild/linux-mips64el": "npm:0.25.6"
|
||||
"@esbuild/linux-ppc64": "npm:0.25.6"
|
||||
"@esbuild/linux-riscv64": "npm:0.25.6"
|
||||
"@esbuild/linux-s390x": "npm:0.25.6"
|
||||
"@esbuild/linux-x64": "npm:0.25.6"
|
||||
"@esbuild/netbsd-arm64": "npm:0.25.6"
|
||||
"@esbuild/netbsd-x64": "npm:0.25.6"
|
||||
"@esbuild/openbsd-arm64": "npm:0.25.6"
|
||||
"@esbuild/openbsd-x64": "npm:0.25.6"
|
||||
"@esbuild/openharmony-arm64": "npm:0.25.6"
|
||||
"@esbuild/sunos-x64": "npm:0.25.6"
|
||||
"@esbuild/win32-arm64": "npm:0.25.6"
|
||||
"@esbuild/win32-ia32": "npm:0.25.6"
|
||||
"@esbuild/win32-x64": "npm:0.25.6"
|
||||
"@esbuild/aix-ppc64": "npm:0.25.8"
|
||||
"@esbuild/android-arm": "npm:0.25.8"
|
||||
"@esbuild/android-arm64": "npm:0.25.8"
|
||||
"@esbuild/android-x64": "npm:0.25.8"
|
||||
"@esbuild/darwin-arm64": "npm:0.25.8"
|
||||
"@esbuild/darwin-x64": "npm:0.25.8"
|
||||
"@esbuild/freebsd-arm64": "npm:0.25.8"
|
||||
"@esbuild/freebsd-x64": "npm:0.25.8"
|
||||
"@esbuild/linux-arm": "npm:0.25.8"
|
||||
"@esbuild/linux-arm64": "npm:0.25.8"
|
||||
"@esbuild/linux-ia32": "npm:0.25.8"
|
||||
"@esbuild/linux-loong64": "npm:0.25.8"
|
||||
"@esbuild/linux-mips64el": "npm:0.25.8"
|
||||
"@esbuild/linux-ppc64": "npm:0.25.8"
|
||||
"@esbuild/linux-riscv64": "npm:0.25.8"
|
||||
"@esbuild/linux-s390x": "npm:0.25.8"
|
||||
"@esbuild/linux-x64": "npm:0.25.8"
|
||||
"@esbuild/netbsd-arm64": "npm:0.25.8"
|
||||
"@esbuild/netbsd-x64": "npm:0.25.8"
|
||||
"@esbuild/openbsd-arm64": "npm:0.25.8"
|
||||
"@esbuild/openbsd-x64": "npm:0.25.8"
|
||||
"@esbuild/openharmony-arm64": "npm:0.25.8"
|
||||
"@esbuild/sunos-x64": "npm:0.25.8"
|
||||
"@esbuild/win32-arm64": "npm:0.25.8"
|
||||
"@esbuild/win32-ia32": "npm:0.25.8"
|
||||
"@esbuild/win32-x64": "npm:0.25.8"
|
||||
dependenciesMeta:
|
||||
"@esbuild/aix-ppc64":
|
||||
optional: true
|
||||
@@ -1344,7 +1355,7 @@ __metadata:
|
||||
optional: true
|
||||
bin:
|
||||
esbuild: bin/esbuild
|
||||
checksum: 10c0/6c2ddc66d8789d75bfa940fddf51a6a98b0fcb474f090669b47091f587e8c3e8e7da57d769b770fd8133268dd5bfc7055318aea0bca6f7c725220d7550437b42
|
||||
checksum: 10c0/43747a25e120d5dd9ce75c82f57306580d715647c8db4f4a0a84e73b04cf16c27572d3937d3cfb95d5ac3266a4d1bbd3913e3d76ae719693516289fc86f8a5fd
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -1786,8 +1797,8 @@ __metadata:
|
||||
linkType: hard
|
||||
|
||||
"less@npm:^4.2.0":
|
||||
version: 4.3.0
|
||||
resolution: "less@npm:4.3.0"
|
||||
version: 4.4.0
|
||||
resolution: "less@npm:4.4.0"
|
||||
dependencies:
|
||||
copy-anything: "npm:^2.0.1"
|
||||
errno: "npm:^0.1.1"
|
||||
@@ -1816,7 +1827,7 @@ __metadata:
|
||||
optional: true
|
||||
bin:
|
||||
lessc: bin/lessc
|
||||
checksum: 10c0/69a9260d4613387fd1f2da3b0904005423272c59f304b27475c145a62f6890be5d38729fd78ef2a65cba3d1d9b02760f309074cad0be4764252934ad04efb2ae
|
||||
checksum: 10c0/843b3f194fcceba2c244db3d51b1d73599410c4919d4e96b572d91a28547e2f09d60cf88e6a28c2df944eb694af1daee09c56e0f0dc4a506b8461777e3334a92
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -1842,9 +1853,9 @@ __metadata:
|
||||
linkType: hard
|
||||
|
||||
"loupe@npm:^3.1.0, loupe@npm:^3.1.4":
|
||||
version: 3.1.4
|
||||
resolution: "loupe@npm:3.1.4"
|
||||
checksum: 10c0/5c2e6aefaad25f812d361c750b8cf4ff91d68de289f141d7c85c2ce9bb79eeefa06a93c85f7b87cba940531ed8f15e492f32681d47eed23842ad1963eb3a154d
|
||||
version: 3.2.0
|
||||
resolution: "loupe@npm:3.2.0"
|
||||
checksum: 10c0/f572fd9e38db8d36ae9eede305480686e310d69bc40394b6842838ebc6c3860a0e35ab30182f33606ab2d8a685d9ff6436649269f8218a1c3385ca329973cb2c
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -2229,10 +2240,10 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"picomatch@npm:^4.0.2":
|
||||
version: 4.0.2
|
||||
resolution: "picomatch@npm:4.0.2"
|
||||
checksum: 10c0/7c51f3ad2bb42c776f49ebf964c644958158be30d0a510efd5a395e8d49cb5acfed5b82c0c5b365523ce18e6ab85013c9ebe574f60305892ec3fa8eee8304ccc
|
||||
"picomatch@npm:^4.0.2, picomatch@npm:^4.0.3":
|
||||
version: 4.0.3
|
||||
resolution: "picomatch@npm:4.0.3"
|
||||
checksum: 10c0/9582c951e95eebee5434f59e426cddd228a7b97a0161a375aed4be244bd3fe8e3a31b846808ea14ef2c8a2527a6eeab7b3946a67d5979e81694654f939473ae2
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -2405,29 +2416,29 @@ __metadata:
|
||||
linkType: hard
|
||||
|
||||
"rollup@npm:^4.40.0":
|
||||
version: 4.44.2
|
||||
resolution: "rollup@npm:4.44.2"
|
||||
version: 4.46.1
|
||||
resolution: "rollup@npm:4.46.1"
|
||||
dependencies:
|
||||
"@rollup/rollup-android-arm-eabi": "npm:4.44.2"
|
||||
"@rollup/rollup-android-arm64": "npm:4.44.2"
|
||||
"@rollup/rollup-darwin-arm64": "npm:4.44.2"
|
||||
"@rollup/rollup-darwin-x64": "npm:4.44.2"
|
||||
"@rollup/rollup-freebsd-arm64": "npm:4.44.2"
|
||||
"@rollup/rollup-freebsd-x64": "npm:4.44.2"
|
||||
"@rollup/rollup-linux-arm-gnueabihf": "npm:4.44.2"
|
||||
"@rollup/rollup-linux-arm-musleabihf": "npm:4.44.2"
|
||||
"@rollup/rollup-linux-arm64-gnu": "npm:4.44.2"
|
||||
"@rollup/rollup-linux-arm64-musl": "npm:4.44.2"
|
||||
"@rollup/rollup-linux-loongarch64-gnu": "npm:4.44.2"
|
||||
"@rollup/rollup-linux-powerpc64le-gnu": "npm:4.44.2"
|
||||
"@rollup/rollup-linux-riscv64-gnu": "npm:4.44.2"
|
||||
"@rollup/rollup-linux-riscv64-musl": "npm:4.44.2"
|
||||
"@rollup/rollup-linux-s390x-gnu": "npm:4.44.2"
|
||||
"@rollup/rollup-linux-x64-gnu": "npm:4.44.2"
|
||||
"@rollup/rollup-linux-x64-musl": "npm:4.44.2"
|
||||
"@rollup/rollup-win32-arm64-msvc": "npm:4.44.2"
|
||||
"@rollup/rollup-win32-ia32-msvc": "npm:4.44.2"
|
||||
"@rollup/rollup-win32-x64-msvc": "npm:4.44.2"
|
||||
"@rollup/rollup-android-arm-eabi": "npm:4.46.1"
|
||||
"@rollup/rollup-android-arm64": "npm:4.46.1"
|
||||
"@rollup/rollup-darwin-arm64": "npm:4.46.1"
|
||||
"@rollup/rollup-darwin-x64": "npm:4.46.1"
|
||||
"@rollup/rollup-freebsd-arm64": "npm:4.46.1"
|
||||
"@rollup/rollup-freebsd-x64": "npm:4.46.1"
|
||||
"@rollup/rollup-linux-arm-gnueabihf": "npm:4.46.1"
|
||||
"@rollup/rollup-linux-arm-musleabihf": "npm:4.46.1"
|
||||
"@rollup/rollup-linux-arm64-gnu": "npm:4.46.1"
|
||||
"@rollup/rollup-linux-arm64-musl": "npm:4.46.1"
|
||||
"@rollup/rollup-linux-loongarch64-gnu": "npm:4.46.1"
|
||||
"@rollup/rollup-linux-ppc64-gnu": "npm:4.46.1"
|
||||
"@rollup/rollup-linux-riscv64-gnu": "npm:4.46.1"
|
||||
"@rollup/rollup-linux-riscv64-musl": "npm:4.46.1"
|
||||
"@rollup/rollup-linux-s390x-gnu": "npm:4.46.1"
|
||||
"@rollup/rollup-linux-x64-gnu": "npm:4.46.1"
|
||||
"@rollup/rollup-linux-x64-musl": "npm:4.46.1"
|
||||
"@rollup/rollup-win32-arm64-msvc": "npm:4.46.1"
|
||||
"@rollup/rollup-win32-ia32-msvc": "npm:4.46.1"
|
||||
"@rollup/rollup-win32-x64-msvc": "npm:4.46.1"
|
||||
"@types/estree": "npm:1.0.8"
|
||||
fsevents: "npm:~2.3.2"
|
||||
dependenciesMeta:
|
||||
@@ -2453,7 +2464,7 @@ __metadata:
|
||||
optional: true
|
||||
"@rollup/rollup-linux-loongarch64-gnu":
|
||||
optional: true
|
||||
"@rollup/rollup-linux-powerpc64le-gnu":
|
||||
"@rollup/rollup-linux-ppc64-gnu":
|
||||
optional: true
|
||||
"@rollup/rollup-linux-riscv64-gnu":
|
||||
optional: true
|
||||
@@ -2475,7 +2486,7 @@ __metadata:
|
||||
optional: true
|
||||
bin:
|
||||
rollup: dist/bin/rollup
|
||||
checksum: 10c0/5ada4fd03e8077888a065bb03f2425501b8402e7cc26f0ffbb454feb61e3a825c8260252a5f768c25481866e798c5ff910f5953c4638ae238d1a14befced02b8
|
||||
checksum: 10c0/84297d63a97bf8fc131039d0f600787ada8baaa38b744820f7d29da601bce9f70a14aa12da80843b2b49eb8660718576f441ee9952954efa16009d7ccebf0000
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -2584,12 +2595,12 @@ __metadata:
|
||||
linkType: hard
|
||||
|
||||
"socks@npm:^2.8.3":
|
||||
version: 2.8.5
|
||||
resolution: "socks@npm:2.8.5"
|
||||
version: 2.8.6
|
||||
resolution: "socks@npm:2.8.6"
|
||||
dependencies:
|
||||
ip-address: "npm:^9.0.5"
|
||||
smart-buffer: "npm:^4.2.0"
|
||||
checksum: 10c0/e427d0eb0451cfd04e20b9156ea8c0e9b5e38a8d70f21e55c30fbe4214eda37cfc25d782c63f9adc5fbdad6d062a0f127ef2cefc9a44b6fee2b9ea5d1ed10827
|
||||
checksum: 10c0/15b95db4caa359c80bfa880ff3e58f3191b9ffa4313570e501a60ee7575f51e4be664a296f4ee5c2c40544da179db6140be53433ce41ec745f9d51f342557514
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -2601,9 +2612,9 @@ __metadata:
|
||||
linkType: hard
|
||||
|
||||
"source-map@npm:^0.7.3":
|
||||
version: 0.7.4
|
||||
resolution: "source-map@npm:0.7.4"
|
||||
checksum: 10c0/dc0cf3768fe23c345ea8760487f8c97ef6fca8a73c83cd7c9bf2fde8bc2c34adb9c0824d6feb14bc4f9e37fb522e18af621543f1289038a66ac7586da29aa7dc
|
||||
version: 0.7.6
|
||||
resolution: "source-map@npm:0.7.6"
|
||||
checksum: 10c0/59f6f05538539b274ba771d2e9e32f6c65451982510564438e048bc1352f019c6efcdc6dd07909b1968144941c14015c2c7d4369fb7c4d7d53ae769716dcc16c
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -2801,7 +2812,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"tslib@npm:^2, tslib@npm:^2.3.0":
|
||||
"tslib@npm:^2, tslib@npm:^2.3.0, tslib@npm:^2.4.0":
|
||||
version: 2.8.1
|
||||
resolution: "tslib@npm:2.8.1"
|
||||
checksum: 10c0/9c4759110a19c53f992d9aae23aac5ced636e99887b51b9e61def52611732872ff7668757d4e4c61f19691e36f4da981cd9485e869b4a7408d689f6bf1f14e62
|
||||
@@ -2809,8 +2820,8 @@ __metadata:
|
||||
linkType: hard
|
||||
|
||||
"typescript-plugin-css-modules@npm:^5":
|
||||
version: 5.1.0
|
||||
resolution: "typescript-plugin-css-modules@npm:5.1.0"
|
||||
version: 5.2.0
|
||||
resolution: "typescript-plugin-css-modules@npm:5.2.0"
|
||||
dependencies:
|
||||
"@types/postcss-modules-local-by-default": "npm:^4.0.2"
|
||||
"@types/postcss-modules-scope": "npm:^3.0.4"
|
||||
@@ -2830,7 +2841,10 @@ __metadata:
|
||||
tsconfig-paths: "npm:^4.2.0"
|
||||
peerDependencies:
|
||||
typescript: ">=4.0.0"
|
||||
checksum: 10c0/a578e9055d015e932e1d42c5329d80d44d7dcaca5990c1d32aed62ea3d7ba49424f18c60cc654e96d1865e509f929359a9e571330ea2f5a7be7c1dd79e25ead3
|
||||
dependenciesMeta:
|
||||
stylus:
|
||||
optional: true
|
||||
checksum: 10c0/7cd024f7145c0a29d9b78f2fb49c42cdf1747b50a43391f9993132ba42a727266f9b544fd868d905d5352e0a8676a19ae7a9aa56d516cc819c3ab39d66aa25e4
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -2909,13 +2923,13 @@ __metadata:
|
||||
linkType: hard
|
||||
|
||||
"vite@npm:^5.0.0 || ^6.0.0 || ^7.0.0-0, vite@npm:^7":
|
||||
version: 7.0.3
|
||||
resolution: "vite@npm:7.0.3"
|
||||
version: 7.0.6
|
||||
resolution: "vite@npm:7.0.6"
|
||||
dependencies:
|
||||
esbuild: "npm:^0.25.0"
|
||||
fdir: "npm:^6.4.6"
|
||||
fsevents: "npm:~2.3.3"
|
||||
picomatch: "npm:^4.0.2"
|
||||
picomatch: "npm:^4.0.3"
|
||||
postcss: "npm:^8.5.6"
|
||||
rollup: "npm:^4.40.0"
|
||||
tinyglobby: "npm:^0.2.14"
|
||||
@@ -2959,7 +2973,7 @@ __metadata:
|
||||
optional: true
|
||||
bin:
|
||||
vite: bin/vite.js
|
||||
checksum: 10c0/9173a1bf9fee82606f39c7b3e785638c1ac7f3473879fc88593f3a2093ed766140a08b845050fd790adb8a36e2cbc81b71401407da05d5dd747ae4f3adb89794
|
||||
checksum: 10c0/3b14dfa661281b4843789884199ba2a9cca940a7666970036fe3fb1abff52b88e63e8be5ab419dd04d9f96c0415ee0f1e3ec8ebe357041648af7ccd8e348b6ad
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
server: {
|
||||
serverPort: "${CLOUDBEAVER_WEB_SERVER_PORT:8978}",
|
||||
secureCookies: "${CLOUDBEAVER_SECURE_COOKIES:true}",
|
||||
forceHttps: "${CLOUDBEAVER_FORCE_HTTPS:false}",
|
||||
|
||||
contentRoot: "web",
|
||||
driversLocation: "drivers",
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
rootURI: "${CLOUDBEAVER_ROOT_URI:/}",
|
||||
serviceURI: "/api/",
|
||||
supportedHosts: [],
|
||||
|
||||
productSettings: {
|
||||
# Global properties
|
||||
@@ -27,7 +28,7 @@
|
||||
},
|
||||
|
||||
expireSessionAfterPeriod: "${CLOUDBEAVER_EXPIRE_SESSION_AFTER_PERIOD:1800000}",
|
||||
bindSessionToIp: "${CLOUDBEAVER_BIND_SESSION_TO_IP:true}",
|
||||
bindSessionToIp: "${CLOUDBEAVER_BIND_SESSION_TO_IP:disable}",
|
||||
develMode: "${CLOUDBEAVER_DEVEL_MODE:false}",
|
||||
|
||||
enableSecurityManager: false,
|
||||
|
||||
@@ -7,6 +7,8 @@ mkdir -p ./cloudbeaver/web
|
||||
|
||||
cd ../../cloudbeaver/common-typescript
|
||||
|
||||
yarn install --immutable
|
||||
cd ../common-react
|
||||
yarn install --immutable
|
||||
cd ../webapp
|
||||
yarn install --immutable
|
||||
@@ -19,6 +21,8 @@ fi
|
||||
|
||||
cd ../../../common-typescript
|
||||
yarn test
|
||||
cd ../common-react
|
||||
yarn test
|
||||
cd ../webapp
|
||||
yarn test
|
||||
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
lefthook: |
|
||||
cd webapp
|
||||
yarn lefthook
|
||||
yarn dlx --quiet lefthook
|
||||
output: false
|
||||
pre-commit:
|
||||
commands:
|
||||
|
||||
@@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2
|
||||
Bundle-Vendor: DBeaver Corp
|
||||
Bundle-Name: Cloudbeaver Web Model
|
||||
Bundle-SymbolicName: io.cloudbeaver.model;singleton:=true
|
||||
Bundle-Version: 1.0.81.qualifier
|
||||
Bundle-Release-Date: 20250721
|
||||
Bundle-Version: 1.0.83.qualifier
|
||||
Bundle-Release-Date: 20250818
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-21
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Require-Bundle: org.jkiss.dbeaver.data.gis;visibility:=reexport,
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
<artifactId>io.cloudbeaver.model</artifactId>
|
||||
<version>1.0.81-SNAPSHOT</version>
|
||||
<version>1.0.83-SNAPSHOT</version>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -30,6 +30,7 @@ public interface DBWConstants {
|
||||
String PERMISSION_PRIVATE_PROJECT_ACCESS = "private-project-access";
|
||||
String PERMISSION_SECRET_MANAGER = "secret-manager";
|
||||
|
||||
String GLOBAL_PERMISSION_SCRIPT_EXECUTE = "permission.sql.script.execution";
|
||||
|
||||
String PERMISSION_EDIT_STRUCTURE = "edit-meta";
|
||||
String PERMISSION_EDIT_DATA = "edit-data";
|
||||
|
||||
@@ -36,4 +36,6 @@ public interface DBWFeatureSet {
|
||||
|
||||
boolean isEnabled();
|
||||
|
||||
boolean isEnabledByDefault();
|
||||
|
||||
}
|
||||
|
||||
+13
@@ -36,6 +36,7 @@ public abstract class BaseWebAppConfiguration implements ServletAppConfiguration
|
||||
protected boolean secretManagerEnabled;
|
||||
protected boolean showReadOnlyConnectionInfo;
|
||||
protected String[] enabledFeatures;
|
||||
protected String[] disabledFeatures;
|
||||
protected String[] disabledBetaFeatures;
|
||||
|
||||
|
||||
@@ -43,6 +44,7 @@ public abstract class BaseWebAppConfiguration implements ServletAppConfiguration
|
||||
this.plugins = new LinkedHashMap<>();
|
||||
this.resourceManagerEnabled = true;
|
||||
this.enabledFeatures = null;
|
||||
this.disabledFeatures = new String[0];
|
||||
this.disabledBetaFeatures = new String[0];
|
||||
this.showReadOnlyConnectionInfo = false;
|
||||
this.secretManagerEnabled = false;
|
||||
@@ -53,6 +55,7 @@ public abstract class BaseWebAppConfiguration implements ServletAppConfiguration
|
||||
this.defaultUserTeam = src.defaultUserTeam;
|
||||
this.resourceManagerEnabled = src.resourceManagerEnabled;
|
||||
this.enabledFeatures = src.enabledFeatures;
|
||||
this.disabledFeatures = src.disabledFeatures;
|
||||
this.disabledBetaFeatures = src.disabledBetaFeatures;
|
||||
this.showReadOnlyConnectionInfo = src.showReadOnlyConnectionInfo;
|
||||
this.secretManagerEnabled = src.secretManagerEnabled;
|
||||
@@ -122,6 +125,16 @@ public abstract class BaseWebAppConfiguration implements ServletAppConfiguration
|
||||
this.enabledFeatures = enabledFeatures;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String[] getDisabledFeatures() {
|
||||
return disabledFeatures;
|
||||
}
|
||||
|
||||
public void setDisabledFeatures(@NotNull String[] disabledFeatures) {
|
||||
this.disabledFeatures = disabledFeatures;
|
||||
}
|
||||
|
||||
public boolean isShowReadOnlyConnectionInfo() {
|
||||
return showReadOnlyConnectionInfo;
|
||||
}
|
||||
|
||||
+10
@@ -51,6 +51,16 @@ public interface ServletAppConfiguration {
|
||||
return new String[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns disabled features.
|
||||
*
|
||||
* @return array of disabled feature IDs
|
||||
*/
|
||||
@NotNull
|
||||
default String[] getDisabledFeatures() {
|
||||
return new String[0];
|
||||
}
|
||||
|
||||
default boolean isSupportsCustomConnections() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -57,7 +57,6 @@ public class CBAppConfig extends BaseWebAppConfiguration implements ServletAuthC
|
||||
private boolean anonymousAccessEnabled;
|
||||
private boolean grantConnectionsAccessToAnonymousTeam;
|
||||
private boolean systemVariablesResolvingEnabled;
|
||||
private boolean apiCallLoggingEnabled;
|
||||
@Deprecated
|
||||
private String anonymousUserRole;
|
||||
private String anonymousUserTeam;
|
||||
@@ -91,7 +90,6 @@ public class CBAppConfig extends BaseWebAppConfiguration implements ServletAuthC
|
||||
this.linkExternalCredentialsWithUser = true;
|
||||
this.grantConnectionsAccessToAnonymousTeam = false;
|
||||
this.systemVariablesResolvingEnabled = false;
|
||||
this.apiCallLoggingEnabled = false;
|
||||
}
|
||||
|
||||
public CBAppConfig(CBAppConfig src) {
|
||||
@@ -116,7 +114,6 @@ public class CBAppConfig extends BaseWebAppConfiguration implements ServletAuthC
|
||||
this.linkExternalCredentialsWithUser = src.linkExternalCredentialsWithUser;
|
||||
this.grantConnectionsAccessToAnonymousTeam = src.grantConnectionsAccessToAnonymousTeam;
|
||||
this.systemVariablesResolvingEnabled = src.systemVariablesResolvingEnabled;
|
||||
this.apiCallLoggingEnabled = src.apiCallLoggingEnabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -357,8 +354,4 @@ public class CBAppConfig extends BaseWebAppConfiguration implements ServletAuthC
|
||||
authConfiguration.clear();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isApiCallLoggingEnabled() {
|
||||
return apiCallLoggingEnabled;
|
||||
}
|
||||
}
|
||||
|
||||
+10
@@ -21,10 +21,12 @@ package io.cloudbeaver.model.config;
|
||||
*/
|
||||
public class ConnectionBruteForceConfiguration {
|
||||
private static final int DEFAULT_ERROR_ATTEMPTS_CHECK_MINUTES = 24 * 60;
|
||||
private static final int BLOCK_TIME_IN_MINUTES = 60;
|
||||
private static final int DEFAULT_MAX_CONNECT_ATTEMPTS = 5;
|
||||
private boolean enabled = false;
|
||||
private int maxFailedConnectAttempts = DEFAULT_MAX_CONNECT_ATTEMPTS;
|
||||
private int errorAttemptsPeriodInMinutes = DEFAULT_ERROR_ATTEMPTS_CHECK_MINUTES;
|
||||
private int blockTimeInMinutes = BLOCK_TIME_IN_MINUTES;
|
||||
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
@@ -49,4 +51,12 @@ public class ConnectionBruteForceConfiguration {
|
||||
public void setErrorAttemptsPeriodInMinutes(int errorAttemptsPeriodInMinutes) {
|
||||
this.errorAttemptsPeriodInMinutes = errorAttemptsPeriodInMinutes;
|
||||
}
|
||||
|
||||
public int getBlockTimeInMinutes() {
|
||||
return blockTimeInMinutes;
|
||||
}
|
||||
|
||||
public void setBlockTimeInMinutes(int blockTimeInMinutes) {
|
||||
this.blockTimeInMinutes = blockTimeInMinutes;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1022,6 +1022,9 @@ public class WebSession extends BaseWebSession
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasGlobalPermission(String permissionId) {
|
||||
return true;
|
||||
}
|
||||
|
||||
private record PersistentAttribute(Object value) {
|
||||
}
|
||||
|
||||
+8
@@ -23,6 +23,7 @@ import org.eclipse.core.runtime.IConfigurationElement;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.dbeaver.model.DBPImage;
|
||||
import org.jkiss.dbeaver.model.impl.AbstractContextDescriptor;
|
||||
import org.jkiss.utils.CommonUtils;
|
||||
|
||||
/**
|
||||
* WebFeatureDescriptor
|
||||
@@ -35,6 +36,7 @@ public class WebFeatureDescriptor extends AbstractContextDescriptor implements D
|
||||
private final String label;
|
||||
private final String description;
|
||||
private final DBPImage icon;
|
||||
private final boolean enabledByDefault;
|
||||
|
||||
public WebFeatureDescriptor(IConfigurationElement config)
|
||||
{
|
||||
@@ -43,6 +45,7 @@ public class WebFeatureDescriptor extends AbstractContextDescriptor implements D
|
||||
this.label = config.getAttribute("label");
|
||||
this.description = config.getAttribute("description");
|
||||
this.icon = iconToImage(config.getAttribute("icon"));
|
||||
this.enabledByDefault = CommonUtils.getBoolean(config.getAttribute("enabledByDefault"), false);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -69,4 +72,9 @@ public class WebFeatureDescriptor extends AbstractContextDescriptor implements D
|
||||
return ServletAppUtils.getServletApplication().getAppConfiguration().isFeatureEnabled(this.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabledByDefault() {
|
||||
return enabledByDefault;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+5
@@ -68,4 +68,9 @@ public class WebServerFeatureDescriptor extends AbstractContextDescriptor implem
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabledByDefault() {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -32,7 +32,9 @@ public class CBConstants {
|
||||
public static final String PARAM_SERVER_PORT = "serverPort";
|
||||
public static final String PARAM_SERVER_HOST = "serverHost";
|
||||
public static final String PARAM_SERVER_NAME = "serverName";
|
||||
public static final String PARAM_SECURE_COOKIES = "secureCookies";
|
||||
public static final String PARAM_FORCE_HTTPS = "forceHttps";
|
||||
public static final String PARAM_BIND_SESSION_TO_IP = "bindSessionToIp";
|
||||
public static final String PARAM_SUPPORTED_HOSTS = "supportedHosts";
|
||||
public static final String PARAM_SSL_CONFIGURATION_PATH = "sslConfigurationPath";
|
||||
public static final String PARAM_CONTENT_ROOT = "contentRoot";
|
||||
public static final String PARAM_SERVER_URL = "serverURL";
|
||||
@@ -93,4 +95,7 @@ public class CBConstants {
|
||||
public static final String ADMIN_AUTO_GRANT = "auto-grant";
|
||||
public static final String HOST_LOCALHOST = "localhost";
|
||||
public static final String HOST_127_0_0_1 = "127.0.0.1";
|
||||
|
||||
public static final String BIND_SESSION_ENABLE = "enable";
|
||||
public static final String BIND_SESSION_DISABLE = "disable";
|
||||
}
|
||||
|
||||
+9
-1
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2024 DBeaver Corp and others
|
||||
* Copyright (C) 2010-2025 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,8 +17,11 @@
|
||||
package io.cloudbeaver.service;
|
||||
|
||||
import io.cloudbeaver.model.app.ServletApplication;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.dbeaver.DBException;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Servlet service
|
||||
*/
|
||||
@@ -28,4 +31,9 @@ public interface DBWServiceBindingServlet<APPLICATION extends ServletApplication
|
||||
}
|
||||
|
||||
void addServlets(APPLICATION application, DBWServletContext servletContext) throws DBException;
|
||||
|
||||
@NotNull
|
||||
default List<String> getExcludedServletPaths(@NotNull APPLICATION application) {
|
||||
return List.of();
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2024 DBeaver Corp and others
|
||||
* Copyright (C) 2010-2025 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -37,6 +37,7 @@ import org.jkiss.dbeaver.utils.GeneralUtils;
|
||||
import org.jkiss.utils.CommonUtils;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
|
||||
@@ -47,6 +48,11 @@ public class ServletAppUtils {
|
||||
|
||||
private static final String HEADER_FORWARDED_SCHEME = "X-Forwarded-Scheme";
|
||||
private static final String HEADER_FORWARDED_HOST = "X-Forwarded-Host";
|
||||
private static final Set<Integer> DEFAULT_PORTS = Set.of(
|
||||
80,
|
||||
443
|
||||
);
|
||||
|
||||
|
||||
private static final Log log = Log.getLog(ServletAppUtils.class);
|
||||
|
||||
@@ -309,7 +315,26 @@ public class ServletAppUtils {
|
||||
if (!origin.endsWith(rootUri)) {
|
||||
origin = origin + "/" + rootUri + "/";
|
||||
}
|
||||
return removeSideSlashes(origin);
|
||||
|
||||
origin = removeSideSlashes(origin);
|
||||
URI uri = URI.create(origin);
|
||||
if (DEFAULT_PORTS.contains(uri.getPort())) {
|
||||
try {
|
||||
origin = new URI(
|
||||
uri.getScheme(),
|
||||
uri.getUserInfo(),
|
||||
uri.getHost(),
|
||||
-1,
|
||||
uri.getPath(),
|
||||
uri.getQuery(),
|
||||
uri.getFragment()
|
||||
).toString();
|
||||
} catch (URISyntaxException e) {
|
||||
log.error("Failed to create URI without port", e);
|
||||
}
|
||||
}
|
||||
|
||||
return origin;
|
||||
}
|
||||
|
||||
public static String getRootUrlFromUri(@NotNull URI uri) {
|
||||
|
||||
@@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2
|
||||
Bundle-Vendor: DBeaver Corp
|
||||
Bundle-Name: Cloudbeaver Community Product
|
||||
Bundle-SymbolicName: io.cloudbeaver.product.ce;singleton:=true
|
||||
Bundle-Version: 25.1.3.qualifier
|
||||
Bundle-Release-Date: 20250721
|
||||
Bundle-Version: 25.1.5.qualifier
|
||||
Bundle-Release-Date: 20250818
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-21
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Require-Bundle: io.cloudbeaver.server.ce
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
<artifactId>io.cloudbeaver.product.ce</artifactId>
|
||||
<version>25.1.3-SNAPSHOT</version>
|
||||
<version>25.1.5-SNAPSHOT</version>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -2,8 +2,8 @@ Manifest-Version: 1.0
|
||||
Bundle-ManifestVersion: 2
|
||||
Bundle-Name: Cloudbeaver Base JDBC drivers
|
||||
Bundle-SymbolicName: io.cloudbeaver.resources.drivers.base;singleton:=true
|
||||
Bundle-Version: 1.0.126.qualifier
|
||||
Bundle-Release-Date: 20250721
|
||||
Bundle-Version: 1.0.128.qualifier
|
||||
Bundle-Release-Date: 20250818
|
||||
Bundle-Vendor: DBeaver Corp
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Automatic-Module-Name: io.cloudbeaver.resources.drivers.base
|
||||
|
||||
@@ -9,6 +9,6 @@
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
<artifactId>io.cloudbeaver.resources.drivers.base</artifactId>
|
||||
<version>1.0.126-SNAPSHOT</version>
|
||||
<version>1.0.128-SNAPSHOT</version>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
</project>
|
||||
|
||||
@@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2
|
||||
Bundle-Vendor: DBeaver Corp
|
||||
Bundle-Name: Cloudbeaver CE Server
|
||||
Bundle-SymbolicName: io.cloudbeaver.server.ce;singleton:=true
|
||||
Bundle-Version: 25.1.3.qualifier
|
||||
Bundle-Release-Date: 20250721
|
||||
Bundle-Version: 25.1.5.qualifier
|
||||
Bundle-Release-Date: 20250818
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-21
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Bundle-Activator: io.cloudbeaver.server.CBPlatformActivator
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
<artifactId>io.cloudbeaver.server.ce</artifactId>
|
||||
<version>25.1.3-SNAPSHOT</version>
|
||||
<version>25.1.5-SNAPSHOT</version>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
extend type ServerConfig {
|
||||
serverURL: String!
|
||||
serverURL: String! @deprecated
|
||||
rootURI: String!
|
||||
hostName: String! @deprecated(reason: "use container id instead")
|
||||
containerId: String!
|
||||
@@ -12,5 +12,11 @@ extend type ServerConfig {
|
||||
redirectOnFederatedAuth: Boolean!
|
||||
enabledAuthProviders: [ID!]!
|
||||
passwordPolicyConfiguration: PasswordPolicyConfig! @since(version: "23.3.3")
|
||||
"Mark all cookies as secure, recommend for HTTPS deployment configurations"
|
||||
forceHttps: Boolean! @since(version: "25.1.3")
|
||||
"List of allowed hosts to use the application - if empty, all hosts are allowed"
|
||||
supportedHosts: [String!]! @since(version: "25.1.3")
|
||||
"Indicates whether the session should be linked to the user's IP address"
|
||||
bindSessionToIp: String! @since(version: "25.1.4")
|
||||
}
|
||||
|
||||
|
||||
+20
-1
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2024 DBeaver Corp and others
|
||||
* Copyright (C) 2010-2025 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -22,6 +22,8 @@ import org.jkiss.code.NotNull;
|
||||
import org.jkiss.dbeaver.model.meta.Property;
|
||||
import org.jkiss.utils.CommonUtils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class CBWebServerConfig extends WebServerConfig {
|
||||
private final CBApplication<?> cbApp;
|
||||
|
||||
@@ -86,4 +88,21 @@ public class CBWebServerConfig extends WebServerConfig {
|
||||
public PasswordPolicyConfiguration getPasswordPolicyConfiguration() {
|
||||
return cbApp.getServerConfiguration().getSecurityManagerConfiguration().getPasswordPolicyConfiguration();
|
||||
}
|
||||
|
||||
@Property
|
||||
public boolean isForceHttps() {
|
||||
return cbApp.getServerConfiguration().isForceHttps();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Property
|
||||
public List<String> getSupportedHosts() {
|
||||
return cbApp.getServerConfiguration().getSupportedHosts();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Property
|
||||
public String getBindSessionToIp() {
|
||||
return cbApp.getServerConfiguration().getBindSessionToIp();
|
||||
}
|
||||
}
|
||||
|
||||
+48
-7
@@ -20,18 +20,21 @@ import com.google.gson.annotations.SerializedName;
|
||||
import io.cloudbeaver.auth.CBAuthConstants;
|
||||
import io.cloudbeaver.model.app.WebServerConfiguration;
|
||||
import io.cloudbeaver.server.CBConstants;
|
||||
import io.cloudbeaver.utils.ServletAppUtils;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.dbeaver.Log;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.net.URI;
|
||||
import java.util.*;
|
||||
|
||||
public class CBServerConfig implements WebServerConfiguration {
|
||||
|
||||
private static final Log log = Log.getLog(CBServerConfig.class);
|
||||
|
||||
protected String serverURL;
|
||||
protected boolean secureCookies;
|
||||
@NotNull
|
||||
protected List<String> supportedHosts = new ArrayList<>();
|
||||
protected boolean forceHttps;
|
||||
protected int serverPort = CBConstants.DEFAULT_SERVER_PORT;
|
||||
private String serverHost = null;
|
||||
private String serverName = null;
|
||||
@@ -52,7 +55,8 @@ public class CBServerConfig implements WebServerConfiguration {
|
||||
@SerializedName("database")
|
||||
private WebDatabaseConfig databaseConfiguration = new WebDatabaseConfig();
|
||||
private String staticContent = "";
|
||||
private boolean bindSessionToIp = true;
|
||||
@NotNull
|
||||
private String bindSessionToIp = CBConstants.BIND_SESSION_DISABLE;
|
||||
|
||||
public CBServerConfig() {
|
||||
this.securityManagerConfiguration = createSecurityManagerConfiguration();
|
||||
@@ -184,11 +188,48 @@ public class CBServerConfig implements WebServerConfiguration {
|
||||
return new SMControllerConfiguration();
|
||||
}
|
||||
|
||||
public boolean isSecureCookies() {
|
||||
return secureCookies;
|
||||
public boolean isForceHttps() {
|
||||
return forceHttps;
|
||||
}
|
||||
|
||||
public boolean isBindSessionToIp() {
|
||||
public void setForceHttps(boolean forceHttps) {
|
||||
this.forceHttps = forceHttps;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<String> getSupportedHosts() {
|
||||
return new ArrayList<>(supportedHosts);
|
||||
}
|
||||
|
||||
public void setSupportedHosts(@NotNull Collection<String> availableHosts) {
|
||||
LinkedHashSet<String> uniqueHosts = new LinkedHashSet<>();
|
||||
for (String host : availableHosts) {
|
||||
try {
|
||||
if (!host.startsWith("http://") && !host.startsWith("https://")) {
|
||||
host = "http://" + host; // Default to HTTP if no scheme is provided to avoid uri parse exception
|
||||
}
|
||||
URI uri = URI.create(host);
|
||||
StringBuilder hostNameBuilder = new StringBuilder();
|
||||
hostNameBuilder.append(ServletAppUtils.removeSideSlashes(uri.getHost() != null ? uri.getHost() : host));
|
||||
if (uri.getPort() > 0) {
|
||||
hostNameBuilder.append(':')
|
||||
.append(uri.getPort());
|
||||
}
|
||||
uniqueHosts.add(hostNameBuilder.toString());
|
||||
} catch (Exception e) {
|
||||
log.error("Invalid host URI: " + host, e);
|
||||
}
|
||||
}
|
||||
this.supportedHosts.clear();
|
||||
this.supportedHosts.addAll(uniqueHosts);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getBindSessionToIp() {
|
||||
return bindSessionToIp;
|
||||
}
|
||||
|
||||
public void setBindSessionToIp(@NotNull String bindSessionToIp) {
|
||||
this.bindSessionToIp = bindSessionToIp;
|
||||
}
|
||||
}
|
||||
|
||||
+26
-1
@@ -27,6 +27,7 @@ import io.cloudbeaver.model.app.ServletSystemInformationCollector;
|
||||
import io.cloudbeaver.model.config.CBAppConfig;
|
||||
import io.cloudbeaver.model.config.CBServerConfig;
|
||||
import io.cloudbeaver.registry.WebDriverRegistry;
|
||||
import io.cloudbeaver.registry.WebFeatureRegistry;
|
||||
import io.cloudbeaver.registry.WebServiceRegistry;
|
||||
import io.cloudbeaver.server.jetty.CBJettyServer;
|
||||
import io.cloudbeaver.service.ConnectionController;
|
||||
@@ -214,7 +215,12 @@ public abstract class CBApplication<T extends CBServerConfig>
|
||||
|
||||
configurationMode = CommonUtils.isEmpty(getServerConfiguration().getServerName());
|
||||
|
||||
refreshDisabledDriversConfig();
|
||||
try {
|
||||
refreshServerConfiguration();
|
||||
} catch (DBException e) {
|
||||
log.error("Error refreshing server configuration", e);
|
||||
return;
|
||||
}
|
||||
|
||||
eventController.setForceSkipEvents(isConfigurationMode()); // do not send events if configuration mode is on
|
||||
|
||||
@@ -331,6 +337,25 @@ public abstract class CBApplication<T extends CBServerConfig>
|
||||
log.debug("Shutdown");
|
||||
}
|
||||
|
||||
private void refreshServerConfiguration() throws DBException {
|
||||
refreshDisabledDriversConfig();
|
||||
refreshEnabledFeatures();
|
||||
if (!isConfigurationMode()) {
|
||||
flushConfiguration();
|
||||
}
|
||||
}
|
||||
|
||||
private void refreshEnabledFeatures() {
|
||||
Set<String> enabledFeatures = new LinkedHashSet<>(Arrays.asList(getAppConfiguration().getEnabledFeatures()));
|
||||
Set<String> disabledFeatures = new LinkedHashSet<>(Arrays.asList(getAppConfiguration().getDisabledFeatures()));
|
||||
|
||||
WebFeatureRegistry.getInstance().getWebFeatures().stream()
|
||||
.filter(f -> f.isEnabledByDefault() && !disabledFeatures.contains(f.getId()))
|
||||
.forEach(f -> enabledFeatures.add(f.getId()));
|
||||
|
||||
getAppConfiguration().setEnabledFeatures(enabledFeatures.toArray(new String[0]));
|
||||
}
|
||||
|
||||
protected ServletSystemInformationCollector<?> createSystemInformationCollector() {
|
||||
return new ServletSystemInformationCollector<>(this);
|
||||
}
|
||||
|
||||
+18
-3
@@ -93,6 +93,7 @@ public abstract class CBServerConfigurationController<T extends CBServerConfig>
|
||||
log.debug("Runtime configuration [" + runtimeConfigPath.toAbsolutePath() + "]");
|
||||
loadConfiguration(runtimeConfigPath);
|
||||
}
|
||||
|
||||
// Set default preferences
|
||||
PrefUtils.setDefaultPreferenceValue(DBWorkbench.getPlatform().getPreferenceStore(),
|
||||
ModelPreferences.UI_DRIVERS_HOME,
|
||||
@@ -107,7 +108,8 @@ public abstract class CBServerConfigurationController<T extends CBServerConfig>
|
||||
return CommonUtils.nullIfEmpty(envValue);
|
||||
}
|
||||
|
||||
public void loadConfiguration(Path configPath) throws DBException {
|
||||
@NotNull
|
||||
public Map<String, Object> loadConfiguration(Path configPath) throws DBException {
|
||||
CBAppConfig prevConfig = new CBAppConfig(appConfiguration);
|
||||
Map<String, Object> configProps = readConfiguration(configPath);
|
||||
try {
|
||||
@@ -123,6 +125,7 @@ public abstract class CBServerConfigurationController<T extends CBServerConfig>
|
||||
mergeOldConfiguration(prevConfig);
|
||||
|
||||
patchConfigurationWithProperties(getServerConfiguration().getProductSettings());
|
||||
return configProps;
|
||||
}
|
||||
|
||||
protected void parseConfiguration(Map<String, Object> configProps) throws DBException {
|
||||
@@ -531,8 +534,20 @@ public abstract class CBServerConfigurationController<T extends CBServerConfig>
|
||||
copyConfigValue(
|
||||
originServerConfig,
|
||||
serverConfigProperties,
|
||||
CBConstants.PARAM_SECURE_COOKIES,
|
||||
serverConfig.isSecureCookies()
|
||||
CBConstants.PARAM_FORCE_HTTPS,
|
||||
serverConfig.isForceHttps()
|
||||
);
|
||||
copyConfigValue(
|
||||
originServerConfig,
|
||||
serverConfigProperties,
|
||||
CBConstants.PARAM_SUPPORTED_HOSTS,
|
||||
serverConfig.getSupportedHosts()
|
||||
);
|
||||
copyConfigValue(
|
||||
originServerConfig,
|
||||
serverConfigProperties,
|
||||
CBConstants.PARAM_BIND_SESSION_TO_IP,
|
||||
serverConfig.getBindSessionToIp()
|
||||
);
|
||||
var productConfigProperties = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
|
||||
Map<String, Object> oldProductRuntimeConfig = JSONUtils.getObject(originServerConfig,
|
||||
|
||||
+20
@@ -22,11 +22,26 @@ import org.jkiss.dbeaver.model.websocket.WSEventHandler;
|
||||
import org.jkiss.dbeaver.model.websocket.event.WSAbstractEvent;
|
||||
import org.jkiss.dbeaver.model.websocket.event.WSUserCloseSessionsEvent;
|
||||
import org.jkiss.dbeaver.model.websocket.event.WSUserDeletedEvent;
|
||||
import org.jkiss.dbeaver.model.websocket.event.WSUserDisabledEvent;
|
||||
|
||||
public class WSUserEventHandler<EVENT extends WSAbstractEvent> implements WSEventHandler<EVENT> {
|
||||
@Override
|
||||
public void handleEvent(@NotNull EVENT event) {
|
||||
var sessionManager = CBApplication.getInstance().getSessionManager();
|
||||
|
||||
switch (event) {
|
||||
case WSUserCloseSessionsEvent closeSessionsEvent -> {
|
||||
if (closeSessionsEvent.getSessionIds().isEmpty()) {
|
||||
sessionManager.closeAllSessions(closeSessionsEvent.getSessionId());
|
||||
} else {
|
||||
sessionManager.closeSessions(closeSessionsEvent.getSessionIds());
|
||||
}
|
||||
}
|
||||
case WSUserDeletedEvent e -> sessionManager.closeUserSession(e);
|
||||
case WSUserDisabledEvent e -> sessionManager.closeUserSession(e);
|
||||
default -> { }
|
||||
}
|
||||
|
||||
switch (event.getId()) {
|
||||
case WSUserCloseSessionsEvent.ID:
|
||||
if (event instanceof WSUserCloseSessionsEvent closeSessionsEvent) {
|
||||
@@ -42,6 +57,11 @@ public class WSUserEventHandler<EVENT extends WSAbstractEvent> implements WSEven
|
||||
sessionManager.closeUserSession(userDeletedEvent);
|
||||
}
|
||||
break;
|
||||
case WSUserDisabledEvent.ID:
|
||||
if (event instanceof WSUserDisabledEvent userDisabledEvent) {
|
||||
sessionManager.closeUserSession(userDisabledEvent);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
+12
-7
@@ -20,8 +20,8 @@ import io.cloudbeaver.model.config.CBServerConfig;
|
||||
import io.cloudbeaver.registry.WebServiceRegistry;
|
||||
import io.cloudbeaver.server.CBApplication;
|
||||
import io.cloudbeaver.server.CBConstants;
|
||||
import io.cloudbeaver.server.graphql.GraphQLEndpoint;
|
||||
import io.cloudbeaver.server.filters.ServerConfigurationTimeLimitFilter;
|
||||
import io.cloudbeaver.server.graphql.GraphQLEndpoint;
|
||||
import io.cloudbeaver.server.servlets.CBImageServlet;
|
||||
import io.cloudbeaver.server.servlets.CBStaticServlet;
|
||||
import io.cloudbeaver.server.servlets.WebStatusServlet;
|
||||
@@ -30,10 +30,7 @@ import io.cloudbeaver.server.websockets.CBWebSocketServerConfigurator;
|
||||
import io.cloudbeaver.service.DBWServiceBindingServlet;
|
||||
import io.cloudbeaver.service.DBWServiceBindingWebSocket;
|
||||
import jakarta.websocket.server.ServerEndpointConfig;
|
||||
import org.eclipse.jetty.ee10.servlet.ErrorPageErrorHandler;
|
||||
import org.eclipse.jetty.ee10.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.ee10.servlet.ServletHolder;
|
||||
import org.eclipse.jetty.ee10.servlet.ServletMapping;
|
||||
import org.eclipse.jetty.ee10.servlet.*;
|
||||
import org.eclipse.jetty.ee10.websocket.jakarta.server.config.JakartaWebSocketServletContainerInitializer;
|
||||
import org.eclipse.jetty.server.*;
|
||||
import org.eclipse.jetty.util.resource.ResourceFactory;
|
||||
@@ -48,6 +45,8 @@ import java.net.InetSocketAddress;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class CBJettyServer {
|
||||
|
||||
@@ -92,6 +91,7 @@ public class CBJettyServer {
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
// Handler configuration
|
||||
Path contentRootPath = Path.of(serverConfiguration.getContentRoot());
|
||||
ServletContextHandler servletContextHandler = new ServletContextHandler(ServletContextHandler.SESSIONS);
|
||||
@@ -99,6 +99,7 @@ public class CBJettyServer {
|
||||
String rootURI = serverConfiguration.getRootURI();
|
||||
servletContextHandler.setContextPath(rootURI);
|
||||
|
||||
|
||||
ServletHolder staticServletHolder = new ServletHolder(
|
||||
"static", new CBStaticServlet(Path.of(serverConfiguration.getContentRoot()))
|
||||
);
|
||||
@@ -126,7 +127,7 @@ public class CBJettyServer {
|
||||
servletContextHandler.addEventListener(new CBServerContextListener(application));
|
||||
|
||||
// Add extensions from services
|
||||
|
||||
Set<String> excludedFilterPaths = new HashSet<>();
|
||||
CBJettyServletContext servletContext = new CBJettyServletContext(servletContextHandler);
|
||||
for (DBWServiceBindingServlet wsd : WebServiceRegistry.getInstance()
|
||||
.getWebServices(DBWServiceBindingServlet.class)
|
||||
@@ -134,6 +135,7 @@ public class CBJettyServer {
|
||||
if (wsd.isApplicable(this.application)) {
|
||||
try {
|
||||
wsd.addServlets(this.application, servletContext);
|
||||
excludedFilterPaths.addAll(wsd.getExcludedServletPaths(this.application));
|
||||
} catch (DBException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
@@ -152,6 +154,9 @@ public class CBJettyServer {
|
||||
}
|
||||
}
|
||||
}
|
||||
FilterHolder hostsFilter = new FilterHolder(new RequestHostFilter(application, excludedFilterPaths));
|
||||
servletContextHandler.addFilter(hostsFilter, "/*", null);
|
||||
|
||||
|
||||
JakartaWebSocketServletContainerInitializer.configure(servletContextHandler, (context, container) -> {
|
||||
// Add echo endpoint to server container
|
||||
@@ -231,7 +236,7 @@ public class CBJettyServer {
|
||||
&& servletContextHandler.getSessionHandler() instanceof CBSessionHandler cbSessionHandler
|
||||
) {
|
||||
cbSessionHandler.setMaxCookieAge((int) (application.getMaxSessionIdleTime() / 1000));
|
||||
cbSessionHandler.setSecureCookies(application.getServerConfiguration().isSecureCookies());
|
||||
cbSessionHandler.setSecureCookies(application.getServerConfiguration().isForceHttps());
|
||||
}
|
||||
}
|
||||
}
|
||||
+146
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2025 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.cloudbeaver.server.jetty;
|
||||
|
||||
import io.cloudbeaver.model.config.CBServerConfig;
|
||||
import io.cloudbeaver.server.CBApplication;
|
||||
import io.cloudbeaver.utils.ServletAppUtils;
|
||||
import jakarta.servlet.*;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.dbeaver.Log;
|
||||
import org.jkiss.utils.CommonUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class RequestHostFilter implements Filter {
|
||||
private static final Log log = Log.getLog(RequestHostFilter.class);
|
||||
|
||||
@NotNull
|
||||
private final CBApplication<?> application;
|
||||
private final Set<String> excludedPaths = new HashSet<>();
|
||||
|
||||
public RequestHostFilter(@NotNull CBApplication<?> application, @NotNull Set<String> excludedPaths) {
|
||||
this.application = application;
|
||||
this.excludedPaths.addAll(
|
||||
excludedPaths.stream()
|
||||
.map(path -> ServletAppUtils.removeSideSlashes(path.replace("*", "")))
|
||||
.toList()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
|
||||
if (request instanceof HttpServletRequest httpRequest) {
|
||||
CBServerConfig serverConfig = application.getServerConfiguration();
|
||||
URI originUri;
|
||||
try {
|
||||
String origin = ServletAppUtils.getOriginFromRequestOrThrow(httpRequest);
|
||||
originUri = URI.create(origin);
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to get origin from request", e);
|
||||
chain.doFilter(request, response);
|
||||
return;
|
||||
}
|
||||
String servletPath = httpRequest.getServletPath();
|
||||
if (CommonUtils.isNotEmpty(servletPath)) {
|
||||
for (String excludedPath : excludedPaths) {
|
||||
if (servletPath.contains(excludedPath)) {
|
||||
chain.doFilter(request, response);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
validateHosts(serverConfig, httpRequest, response, originUri);
|
||||
validateSchema(serverConfig, httpRequest, response, originUri);
|
||||
|
||||
}
|
||||
chain.doFilter(request, response);
|
||||
}
|
||||
|
||||
private void validateSchema(CBServerConfig serverConfig, HttpServletRequest httpRequest, ServletResponse response, URI originUri) {
|
||||
boolean httpsExpected = serverConfig.isForceHttps();
|
||||
try {
|
||||
if ("http".equals(originUri.getScheme()) && httpsExpected) {
|
||||
log.warn("Request schema is 'http' but 'forceHttps' is enabled. Redirecting to 'https'.");
|
||||
StringBuilder redirectUrlBuilder = new StringBuilder("https://")
|
||||
.append(originUri.getHost());
|
||||
if (originUri.getPort() > -1) {
|
||||
redirectUrlBuilder.append(':').append(originUri.getPort());
|
||||
}
|
||||
redirectUrlBuilder.append(httpRequest.getRequestURI());
|
||||
if (httpRequest.getQueryString() != null) {
|
||||
redirectUrlBuilder.append("?")
|
||||
.append(httpRequest.getQueryString());
|
||||
}
|
||||
((HttpServletResponse) response).sendRedirect(redirectUrlBuilder.toString());
|
||||
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to redirect to HTTPS", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void validateHosts(
|
||||
@NotNull CBServerConfig serverConfig,
|
||||
@NotNull HttpServletRequest httpRequest,
|
||||
@NotNull ServletResponse response,
|
||||
URI originUri
|
||||
) throws IOException {
|
||||
List<String> availableHosts = serverConfig.getSupportedHosts();
|
||||
if (CommonUtils.isEmpty(availableHosts)) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
var requestHostBuilder = new StringBuilder(originUri.getHost());
|
||||
if (originUri.getPort() > -1) {
|
||||
requestHostBuilder.append(':').append(originUri.getPort());
|
||||
}
|
||||
String requestHost = requestHostBuilder.toString();
|
||||
if (!availableHosts.contains(requestHost)) {
|
||||
log.warn("Request host '" + requestHost + "' is not allowed. Redirect to default: " + availableHosts);
|
||||
redirectToDefaultHost((HttpServletResponse) response, httpRequest, availableHosts);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
log.error(e.getMessage(), e);
|
||||
redirectToDefaultHost((HttpServletResponse) response, httpRequest, availableHosts);
|
||||
}
|
||||
}
|
||||
|
||||
private void redirectToDefaultHost(
|
||||
@NotNull HttpServletResponse response,
|
||||
@NotNull HttpServletRequest httpRequest,
|
||||
@NotNull List<String> availableHosts
|
||||
) throws IOException {
|
||||
boolean https = application.getServerConfiguration().isForceHttps();
|
||||
String redirectUrl = (https ? "https://" : "http://") + getDefaultHost(availableHosts) + httpRequest.getRequestURI();
|
||||
if (httpRequest.getQueryString() != null) {
|
||||
redirectUrl += "?" + httpRequest.getQueryString();
|
||||
}
|
||||
response.sendRedirect(redirectUrl);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private String getDefaultHost(@NotNull List<String> availableHosts) {
|
||||
return availableHosts.getFirst();
|
||||
}
|
||||
}
|
||||
+18
-5
@@ -22,6 +22,7 @@ import io.cloudbeaver.model.session.*;
|
||||
import io.cloudbeaver.registry.WebHandlerRegistry;
|
||||
import io.cloudbeaver.registry.WebSessionHandlerDescriptor;
|
||||
import io.cloudbeaver.server.CBApplication;
|
||||
import io.cloudbeaver.server.CBConstants;
|
||||
import io.cloudbeaver.server.WebAppSessionManager;
|
||||
import io.cloudbeaver.server.events.WSWebUtils;
|
||||
import io.cloudbeaver.service.DBWSessionHandler;
|
||||
@@ -34,7 +35,9 @@ import org.jkiss.dbeaver.DBException;
|
||||
import org.jkiss.dbeaver.Log;
|
||||
import org.jkiss.dbeaver.model.auth.SMAuthInfo;
|
||||
import org.jkiss.dbeaver.model.security.user.SMAuthPermissions;
|
||||
import org.jkiss.dbeaver.model.websocket.event.WSAbstractEvent;
|
||||
import org.jkiss.dbeaver.model.websocket.event.WSUserDeletedEvent;
|
||||
import org.jkiss.dbeaver.model.websocket.event.WSUserDisabledEvent;
|
||||
import org.jkiss.dbeaver.model.websocket.event.session.WSSessionStateEvent;
|
||||
import org.jkiss.utils.CommonUtils;
|
||||
|
||||
@@ -156,8 +159,15 @@ public class CBSessionManager implements WebAppSessionManager {
|
||||
}
|
||||
}
|
||||
|
||||
validateSessionIp(request, webSession);
|
||||
|
||||
return webSession;
|
||||
}
|
||||
|
||||
private void validateSessionIp(@NotNull HttpServletRequest request, WebSession webSession) {
|
||||
boolean bindingEnabled = isSessionBindingEnabled(request);
|
||||
String currentRemote = request.getRemoteAddr();
|
||||
if (application.getServerConfiguration().isBindSessionToIp()
|
||||
if (bindingEnabled
|
||||
&& (CommonUtils.isEmpty(currentRemote) || !currentRemote.equals(webSession.getLastRemoteAddr()))
|
||||
) {
|
||||
var error = new DBWebException(
|
||||
@@ -169,8 +179,11 @@ public class CBSessionManager implements WebAppSessionManager {
|
||||
webSession.addSessionError(error);
|
||||
closeSession(webSession.getSessionId());
|
||||
}
|
||||
}
|
||||
|
||||
return webSession;
|
||||
protected boolean isSessionBindingEnabled(@NotNull HttpServletRequest request) {
|
||||
String bindingState = application.getServerConfiguration().getBindSessionToIp();
|
||||
return CBConstants.BIND_SESSION_ENABLE.equalsIgnoreCase(bindingState) || Boolean.parseBoolean(bindingState);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -391,14 +404,14 @@ public class CBSessionManager implements WebAppSessionManager {
|
||||
}
|
||||
}
|
||||
|
||||
public void closeUserSession(@NotNull WSUserDeletedEvent userDeletedEvent) {
|
||||
public void closeUserSession(@NotNull WSAbstractEvent event) {
|
||||
synchronized (sessionMap) {
|
||||
for (Iterator<BaseWebSession> iterator = sessionMap.values().iterator(); iterator.hasNext(); ) {
|
||||
var session = iterator.next();
|
||||
if (CommonUtils.equalObjects(session.getUserContext().getUserId(),
|
||||
userDeletedEvent.getDeletedUserId())) {
|
||||
event.getUserId())) {
|
||||
if (session instanceof WebHeadlessSession headlessSession) {
|
||||
headlessSession.addSessionEvent(userDeletedEvent);
|
||||
headlessSession.addSessionEvent(event);
|
||||
}
|
||||
iterator.remove();
|
||||
session.close();
|
||||
|
||||
@@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2
|
||||
Bundle-Vendor: DBeaver Corp
|
||||
Bundle-Name: Cloudbeaver Web Server
|
||||
Bundle-SymbolicName: io.cloudbeaver.server;singleton:=true
|
||||
Bundle-Version: 25.1.3.qualifier
|
||||
Bundle-Release-Date: 20250721
|
||||
Bundle-Version: 25.1.5.qualifier
|
||||
Bundle-Release-Date: 20250818
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-21
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Require-Bundle: org.eclipse.core.runtime;visibility:=reexport,
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
log.api.graphql.debug = Enable detailed logging
|
||||
log.api.graphql.debug = Log GraphQL requests to console
|
||||
log.api.graphql.debug.description = Enable detailed logging of GraphQL queries in the server log, including all provided variables
|
||||
@@ -1,2 +1,2 @@
|
||||
log.api.graphql.debug = Включить подробное логирование
|
||||
log.api.graphql.debug =Логировать GraphQL-запросы в консоль
|
||||
log.api.graphql.debug.description = Включите подробное логирование запросов GraphQL в журнале сервера, включая все предоставленные переменные
|
||||
@@ -64,9 +64,9 @@
|
||||
|
||||
<extension point="org.jkiss.dbeaver.settings">
|
||||
<propertyGroup id="log" label="Logger">
|
||||
<property id="log.api.graphql.debug" label="Enable detailed logging"
|
||||
<property id="log.api.graphql.debug" label="%log.api.graphql.debug"
|
||||
type="boolean" scopes="global"
|
||||
description="Enable detailed logging of GraphQL queries in the server log, including all provided variables"/>
|
||||
description="%log.api.graphql.debug.description"/>
|
||||
</propertyGroup>
|
||||
</extension>
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
<artifactId>io.cloudbeaver.server</artifactId>
|
||||
<version>25.1.3-SNAPSHOT</version>
|
||||
<version>25.1.5-SNAPSHOT</version>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2024 DBeaver Corp and others
|
||||
* Copyright (C) 2010-2025 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -35,4 +35,6 @@ public @interface WebAction {
|
||||
|
||||
boolean initializationRequired() default true;
|
||||
|
||||
String[] requireGlobalPermissions() default {};
|
||||
|
||||
}
|
||||
|
||||
+8
-7
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2024 DBeaver Corp and others
|
||||
* Copyright (C) 2010-2025 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -18,22 +18,23 @@ package io.cloudbeaver.model;
|
||||
|
||||
import io.cloudbeaver.model.session.WebSession;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.dbeaver.model.impl.PropertyDescriptor;
|
||||
import org.jkiss.dbeaver.model.impl.PropertyGroupDescriptor;
|
||||
import org.jkiss.dbeaver.model.meta.Property;
|
||||
import org.jkiss.dbeaver.registry.settings.ProductSettingDescriptor;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class WebProductSettings {
|
||||
public class WebGroupPropertiesInfo<T extends PropertyDescriptor> {
|
||||
@NotNull
|
||||
private final WebSession webSession;
|
||||
@NotNull
|
||||
private final List<PropertyGroupDescriptor<ProductSettingDescriptor>> groups;
|
||||
private final Collection<PropertyGroupDescriptor<T>> groups;
|
||||
|
||||
public WebProductSettings(
|
||||
public WebGroupPropertiesInfo(
|
||||
@NotNull WebSession webSession,
|
||||
@NotNull List<PropertyGroupDescriptor<ProductSettingDescriptor>> groups
|
||||
@NotNull Collection<PropertyGroupDescriptor<T>> groups
|
||||
) {
|
||||
this.webSession = webSession;
|
||||
this.groups = groups;
|
||||
@@ -41,7 +42,7 @@ public class WebProductSettings {
|
||||
|
||||
@NotNull
|
||||
@Property
|
||||
public List<WebSettingsGroupInfo> getGroups() {
|
||||
public List<WebSettingsGroupInfo<T>> getGroups() {
|
||||
return groups.stream()
|
||||
.map(WebSettingsGroupInfo::new)
|
||||
.collect(Collectors.toList());
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2024 DBeaver Corp and others
|
||||
* Copyright (C) 2010-2025 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
+5
-5
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2024 DBeaver Corp and others
|
||||
* Copyright (C) 2010-2025 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,15 +17,15 @@
|
||||
package io.cloudbeaver.model;
|
||||
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.dbeaver.model.impl.PropertyDescriptor;
|
||||
import org.jkiss.dbeaver.model.impl.PropertyGroupDescriptor;
|
||||
import org.jkiss.dbeaver.model.meta.Property;
|
||||
import org.jkiss.dbeaver.registry.settings.ProductSettingDescriptor;
|
||||
|
||||
public class WebSettingsGroupInfo {
|
||||
public class WebSettingsGroupInfo<T extends PropertyDescriptor> {
|
||||
@NotNull
|
||||
private final PropertyGroupDescriptor<ProductSettingDescriptor> groupDescriptor;
|
||||
private final PropertyGroupDescriptor<T> groupDescriptor;
|
||||
|
||||
public WebSettingsGroupInfo(@NotNull PropertyGroupDescriptor<ProductSettingDescriptor> groupDescriptor) {
|
||||
public WebSettingsGroupInfo(@NotNull PropertyGroupDescriptor<T> groupDescriptor) {
|
||||
this.groupDescriptor = groupDescriptor;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -33,7 +33,7 @@ public class WebObjectFeatureRegistry {
|
||||
|
||||
private final List<WebObjectFeatureProviderDescriptor> providers = new ArrayList<>();
|
||||
|
||||
public static WebObjectFeatureRegistry getInstance() {
|
||||
public static synchronized WebObjectFeatureRegistry getInstance() {
|
||||
if (INSTANCE == null) {
|
||||
INSTANCE = new WebObjectFeatureRegistry();
|
||||
INSTANCE.loadExtensions(Platform.getExtensionRegistry());
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2024 DBeaver Corp and others
|
||||
* Copyright (C) 2010-2025 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
+10
-2
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2024 DBeaver Corp and others
|
||||
* Copyright (C) 2010-2025 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -265,7 +265,8 @@ public abstract class WebServiceBindingBase<API_TYPE extends DBWService> impleme
|
||||
throw new DBWebExceptionServerNotInitialized(message);
|
||||
}
|
||||
String[] reqPermissions = webAction.requirePermissions();
|
||||
if (reqPermissions.length == 0 && !webAction.authRequired()) {
|
||||
String[] reqGlobalPermissions = webAction.requireGlobalPermissions();
|
||||
if (reqPermissions.length == 0 && reqGlobalPermissions.length == 0 && !webAction.authRequired()) {
|
||||
return;
|
||||
}
|
||||
WebSession session = findWebSession(env);
|
||||
@@ -297,6 +298,13 @@ public abstract class WebServiceBindingBase<API_TYPE extends DBWService> impleme
|
||||
throw new DBWebExceptionAccessDenied("Access denied");
|
||||
}
|
||||
}
|
||||
// Check permissions
|
||||
for (String gp : reqGlobalPermissions) {
|
||||
if (!session.hasGlobalPermission(gp)) {
|
||||
log.debug("Access to " + method.getName() + " denied for " + session.getUser());
|
||||
throw new DBWebExceptionAccessDenied("Access denied");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -29,6 +29,7 @@ import org.jkiss.code.NotNull;
|
||||
import org.jkiss.code.Nullable;
|
||||
import org.jkiss.dbeaver.model.navigator.DBNBrowseSettings;
|
||||
import org.jkiss.dbeaver.model.rm.RMConstants;
|
||||
import org.jkiss.dbeaver.registry.settings.ProductSettingDescriptor;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -48,7 +49,7 @@ public interface DBWServiceCore extends DBWService {
|
||||
WebPropertyInfo[] getSystemInformationProperties(@NotNull WebSession webSession);
|
||||
|
||||
@WebAction
|
||||
WebProductSettings getProductSettings(@NotNull WebSession webSession);
|
||||
WebGroupPropertiesInfo<ProductSettingDescriptor> getProductSettings(@NotNull WebSession webSession);
|
||||
|
||||
@WebAction
|
||||
List<WebDatabaseDriverInfo> getDriverList(@NotNull WebSession webSession, String driverId) throws DBWebException;
|
||||
|
||||
+3
-2
@@ -54,6 +54,7 @@ import org.jkiss.dbeaver.registry.DataSourceDescriptor;
|
||||
import org.jkiss.dbeaver.registry.DataSourceProviderRegistry;
|
||||
import org.jkiss.dbeaver.registry.network.NetworkHandlerDescriptor;
|
||||
import org.jkiss.dbeaver.registry.network.NetworkHandlerRegistry;
|
||||
import org.jkiss.dbeaver.registry.settings.ProductSettingDescriptor;
|
||||
import org.jkiss.dbeaver.registry.settings.ProductSettingsRegistry;
|
||||
import org.jkiss.dbeaver.runtime.DBWorkbench;
|
||||
import org.jkiss.utils.CommonUtils;
|
||||
@@ -644,8 +645,8 @@ public class WebServiceCore implements DBWServiceCore {
|
||||
}
|
||||
|
||||
@Override
|
||||
public WebProductSettings getProductSettings(@NotNull WebSession webSession) {
|
||||
return new WebProductSettings(webSession, ProductSettingsRegistry.getInstance().getSettings());
|
||||
public WebGroupPropertiesInfo<ProductSettingDescriptor> getProductSettings(@NotNull WebSession webSession) {
|
||||
return new WebGroupPropertiesInfo<>(webSession, ProductSettingsRegistry.getInstance().getSettings());
|
||||
}
|
||||
|
||||
private WebSessionProjectImpl getProjectById(WebSession webSession, String projectId) throws DBWebException {
|
||||
|
||||
+2
-1
@@ -16,6 +16,7 @@
|
||||
*/
|
||||
package io.cloudbeaver.service.sql;
|
||||
|
||||
import io.cloudbeaver.DBWConstants;
|
||||
import io.cloudbeaver.DBWebException;
|
||||
import io.cloudbeaver.WebAction;
|
||||
import io.cloudbeaver.model.WebAsyncTaskInfo;
|
||||
@@ -90,7 +91,7 @@ public interface DBWServiceSQL extends DBWService {
|
||||
@WebAction
|
||||
void setContextDefaults(@NotNull WebSQLContextInfo sqlContext, String catalogName, String schemaName) throws DBWebException;
|
||||
|
||||
@WebAction
|
||||
@WebAction(requireGlobalPermissions = DBWConstants.GLOBAL_PERMISSION_SCRIPT_EXECUTE)
|
||||
WebAsyncTaskInfo asyncExecuteQuery(
|
||||
@NotNull WebSQLContextInfo contextInfo,
|
||||
@NotNull String sql,
|
||||
|
||||
@@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2
|
||||
Bundle-Vendor: DBeaver Corp
|
||||
Bundle-Name: Cloudbeaver Web Service - Administration
|
||||
Bundle-SymbolicName: io.cloudbeaver.service.admin;singleton:=true
|
||||
Bundle-Version: 1.0.125.qualifier
|
||||
Bundle-Release-Date: 20250721
|
||||
Bundle-Version: 1.0.127.qualifier
|
||||
Bundle-Release-Date: 20250818
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-21
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Require-Bundle: io.cloudbeaver.server.ce,
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
<artifactId>io.cloudbeaver.service.admin</artifactId>
|
||||
<version>1.0.125-SNAPSHOT</version>
|
||||
<version>1.0.127-SNAPSHOT</version>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -108,7 +108,7 @@ type WebFeatureSet {
|
||||
|
||||
input ServerConfigInput {
|
||||
serverName: String
|
||||
serverURL: String
|
||||
serverURL: String @deprecated
|
||||
|
||||
adminName: String
|
||||
adminPassword: String
|
||||
@@ -126,6 +126,9 @@ input ServerConfigInput {
|
||||
disabledDrivers: [ID!]
|
||||
|
||||
sessionExpireTime: Int
|
||||
forceHttps: Boolean @since(version: "25.1.3")
|
||||
supportedHosts: [String!] @since(version: "25.1.3")
|
||||
bindSessionToIp: String @since(version: "25.1.4")
|
||||
}
|
||||
|
||||
input AdminUserFilterInput {
|
||||
|
||||
+54
-3
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2024 DBeaver Corp and others
|
||||
* Copyright (C) 2010-2025 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -18,6 +18,9 @@ package io.cloudbeaver.service.admin;
|
||||
|
||||
import io.cloudbeaver.model.config.CBAppConfig;
|
||||
import io.cloudbeaver.server.CBApplication;
|
||||
import io.cloudbeaver.server.CBConstants;
|
||||
import org.jkiss.code.Nullable;
|
||||
import org.jkiss.dbeaver.Log;
|
||||
import org.jkiss.dbeaver.model.data.json.JSONUtils;
|
||||
|
||||
import java.util.Arrays;
|
||||
@@ -28,6 +31,7 @@ import java.util.Map;
|
||||
* Server configuration for admin API
|
||||
*/
|
||||
public class AdminServerConfig {
|
||||
private static final Log log = Log.getLog(AdminServerConfig.class);
|
||||
|
||||
private String serverName;
|
||||
private String serverURL;
|
||||
@@ -45,8 +49,14 @@ public class AdminServerConfig {
|
||||
private final List<String> enabledAuthProviders;
|
||||
private final String[] enabledDrivers;
|
||||
private final String[] disabledDrivers;
|
||||
@Nullable
|
||||
private final Boolean forceHttps;
|
||||
@Nullable
|
||||
private final List<String> supportedHosts;
|
||||
|
||||
private long sessionExpireTime;
|
||||
@Nullable
|
||||
private String bindSessionToIp;
|
||||
|
||||
public AdminServerConfig(Map<String, Object> params) {
|
||||
this.serverName = JSONUtils.getString(params, "serverName");
|
||||
@@ -57,8 +67,16 @@ public class AdminServerConfig {
|
||||
CBAppConfig appConfig = CBApplication.getInstance().getAppConfiguration();
|
||||
this.anonymousAccessEnabled = JSONUtils.getBoolean(params, "anonymousAccessEnabled", appConfig.isAnonymousAccessEnabled());
|
||||
this.customConnectionsEnabled = JSONUtils.getBoolean(params, "customConnectionsEnabled", appConfig.isSupportsCustomConnections());
|
||||
this.publicCredentialsSaveEnabled = JSONUtils.getBoolean(params, "publicCredentialsSaveEnabled", appConfig.isPublicCredentialsSaveEnabled());
|
||||
this.adminCredentialsSaveEnabled = JSONUtils.getBoolean(params, "adminCredentialsSaveEnabled", appConfig.isAdminCredentialsSaveEnabled());
|
||||
this.publicCredentialsSaveEnabled = JSONUtils.getBoolean(
|
||||
params,
|
||||
"publicCredentialsSaveEnabled",
|
||||
appConfig.isPublicCredentialsSaveEnabled()
|
||||
);
|
||||
this.adminCredentialsSaveEnabled = JSONUtils.getBoolean(
|
||||
params,
|
||||
"adminCredentialsSaveEnabled",
|
||||
appConfig.isAdminCredentialsSaveEnabled()
|
||||
);
|
||||
this.resourceManagerEnabled = JSONUtils.getBoolean(params, "resourceManagerEnabled", appConfig.isResourceManagerEnabled());
|
||||
this.secretManagerEnabled = JSONUtils.getBoolean(params, "secretManagerEnabled", appConfig.isSecretManagerEnabled());
|
||||
|
||||
@@ -87,6 +105,24 @@ public class AdminServerConfig {
|
||||
} else {
|
||||
this.disabledDrivers = appConfig.getDisabledDrivers();
|
||||
}
|
||||
|
||||
if (params.containsKey(CBConstants.PARAM_FORCE_HTTPS)) {
|
||||
this.forceHttps = JSONUtils.getBoolean(params, CBConstants.PARAM_FORCE_HTTPS);
|
||||
} else {
|
||||
this.forceHttps = null;
|
||||
}
|
||||
|
||||
if (params.containsKey(CBConstants.PARAM_SUPPORTED_HOSTS)) {
|
||||
this.supportedHosts = JSONUtils.getStringList(params, CBConstants.PARAM_SUPPORTED_HOSTS);
|
||||
} else {
|
||||
this.supportedHosts = null;
|
||||
}
|
||||
|
||||
if (params.containsKey("bindSessionToIp")) {
|
||||
this.bindSessionToIp = JSONUtils.getString(params, "bindSessionToIp");
|
||||
} else {
|
||||
this.bindSessionToIp = CBConstants.BIND_SESSION_DISABLE;
|
||||
}
|
||||
}
|
||||
|
||||
public String getServerName() {
|
||||
@@ -168,4 +204,19 @@ public class AdminServerConfig {
|
||||
public boolean isSecretManagerEnabled() {
|
||||
return secretManagerEnabled;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public List<String> getSupportedHosts() {
|
||||
return supportedHosts;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Boolean getForceHttps() {
|
||||
return forceHttps;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getBindSessionToIp() {
|
||||
return bindSessionToIp;
|
||||
}
|
||||
}
|
||||
|
||||
+19
-1
@@ -584,7 +584,7 @@ public class WebServiceAdmin implements DBWServiceAdmin {
|
||||
appConfig.setSupportsCustomConnections(config.isCustomConnectionsEnabled());
|
||||
appConfig.setPublicCredentialsSaveEnabled(config.isPublicCredentialsSaveEnabled());
|
||||
appConfig.setAdminCredentialsSaveEnabled(config.isAdminCredentialsSaveEnabled());
|
||||
appConfig.setEnabledFeatures(config.getEnabledFeatures().toArray(new String[0]));
|
||||
updateDisabledFeaturesConfig(appConfig, config.getEnabledFeatures());
|
||||
// custom logic for enabling embedded drivers
|
||||
updateDisabledDriversConfig(appConfig, config.getDisabledDrivers());
|
||||
appConfig.setResourceManagerEnabled(config.isResourceManagerEnabled());
|
||||
@@ -605,6 +605,15 @@ public class WebServiceAdmin implements DBWServiceAdmin {
|
||||
serverConfig.setServerName(config.getServerName());
|
||||
serverConfig.setServerURL(config.getServerURL());
|
||||
serverConfig.setMaxSessionIdleTime(config.getSessionExpireTime());
|
||||
if (config.getForceHttps() != null) {
|
||||
serverConfig.setForceHttps(config.getForceHttps());
|
||||
}
|
||||
if (config.getSupportedHosts() != null) {
|
||||
serverConfig.setSupportedHosts(config.getSupportedHosts());
|
||||
}
|
||||
if (config.getBindSessionToIp() != null) {
|
||||
serverConfig.setBindSessionToIp(config.getBindSessionToIp());
|
||||
}
|
||||
}
|
||||
|
||||
if (CommonUtils.isEmpty(adminName)) {
|
||||
@@ -665,6 +674,15 @@ public class WebServiceAdmin implements DBWServiceAdmin {
|
||||
return true;
|
||||
}
|
||||
|
||||
private void updateDisabledFeaturesConfig(CBAppConfig appConfig, List<String> enabledFeatures) {
|
||||
Set<String> enabledIds = new LinkedHashSet<>(enabledFeatures);
|
||||
appConfig.setEnabledFeatures(enabledFeatures.toArray(new String[0]));
|
||||
String[] disabledFeatures = WebFeatureRegistry.getInstance().getWebFeatures().stream().map(DBWFeatureSet::getId)
|
||||
.filter(id -> !enabledIds.contains(id))
|
||||
.toArray(String[]::new);
|
||||
appConfig.setDisabledFeatures(disabledFeatures);
|
||||
}
|
||||
|
||||
// we disable embedded drivers by default and enable it in enabled drivers list
|
||||
// that's why we need so complicated logic for disabling drivers
|
||||
private void updateDisabledDriversConfig(CBAppConfig appConfig, String[] disabledDriversConfig) {
|
||||
|
||||
@@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2
|
||||
Bundle-Vendor: DBeaver Corp
|
||||
Bundle-Name: Cloudbeaver Web Service - Authentication
|
||||
Bundle-SymbolicName: io.cloudbeaver.service.auth;singleton:=true
|
||||
Bundle-Version: 1.0.125.qualifier
|
||||
Bundle-Release-Date: 20250721
|
||||
Bundle-Version: 1.0.127.qualifier
|
||||
Bundle-Release-Date: 20250818
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-21
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Require-Bundle: io.cloudbeaver.server.ce
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
<artifactId>io.cloudbeaver.service.auth</artifactId>
|
||||
<version>1.0.125-SNAPSHOT</version>
|
||||
<version>1.0.127-SNAPSHOT</version>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2
|
||||
Bundle-Vendor: DBeaver Corp
|
||||
Bundle-Name: Cloudbeaver Web Service - Data Transfer
|
||||
Bundle-SymbolicName: io.cloudbeaver.service.data.transfer;singleton:=true
|
||||
Bundle-Version: 1.0.126.qualifier
|
||||
Bundle-Release-Date: 20250721
|
||||
Bundle-Version: 1.0.128.qualifier
|
||||
Bundle-Release-Date: 20250818
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-21
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Require-Bundle: io.cloudbeaver.server.ce,
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
<artifactId>io.cloudbeaver.service.data.transfer</artifactId>
|
||||
<version>1.0.126-SNAPSHOT</version>
|
||||
<version>1.0.128-SNAPSHOT</version>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2
|
||||
Bundle-Vendor: DBeaver Corp
|
||||
Bundle-Name: Cloudbeaver Web Service - File System
|
||||
Bundle-SymbolicName: io.cloudbeaver.service.fs;singleton:=true
|
||||
Bundle-Version: 1.0.43.qualifier
|
||||
Bundle-Release-Date: 20250721
|
||||
Bundle-Version: 1.0.45.qualifier
|
||||
Bundle-Release-Date: 20250818
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-21
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Require-Bundle: io.cloudbeaver.server.ce,
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
<artifactId>io.cloudbeaver.service.fs</artifactId>
|
||||
<version>1.0.43-SNAPSHOT</version>
|
||||
<version>1.0.45-SNAPSHOT</version>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2
|
||||
Bundle-Name: Cloudbeaver Web Service - LDAP
|
||||
Bundle-Vendor: DBeaver Corp
|
||||
Bundle-SymbolicName: io.cloudbeaver.service.ldap.auth;singleton:=true
|
||||
Bundle-Version: 1.0.8.qualifier
|
||||
Bundle-Release-Date: 20250721
|
||||
Bundle-Version: 1.0.10.qualifier
|
||||
Bundle-Release-Date: 20250818
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-21
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Require-Bundle: org.jkiss.dbeaver.model;visibility:=reexport,
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
<artifactId>io.cloudbeaver.service.ldap.auth</artifactId>
|
||||
<version>1.0.8-SNAPSHOT</version>
|
||||
<version>1.0.10-SNAPSHOT</version>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2
|
||||
Bundle-Vendor: DBeaver Corp
|
||||
Bundle-Name: Cloudbeaver Web Service - Metadata
|
||||
Bundle-SymbolicName: io.cloudbeaver.service.metadata;singleton:=true
|
||||
Bundle-Version: 1.0.129.qualifier
|
||||
Bundle-Release-Date: 20250721
|
||||
Bundle-Version: 1.0.131.qualifier
|
||||
Bundle-Release-Date: 20250818
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-21
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Require-Bundle: io.cloudbeaver.server
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
<artifactId>io.cloudbeaver.service.metadata</artifactId>
|
||||
<version>1.0.129-SNAPSHOT</version>
|
||||
<version>1.0.131-SNAPSHOT</version>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2
|
||||
Bundle-Vendor: DBeaver Corp
|
||||
Bundle-Name: Cloudbeaver Resource manager NIO implementation
|
||||
Bundle-SymbolicName: io.cloudbeaver.service.rm.nio;singleton:=true
|
||||
Bundle-Version: 1.0.43.qualifier
|
||||
Bundle-Release-Date: 20250721
|
||||
Bundle-Version: 1.0.45.qualifier
|
||||
Bundle-Release-Date: 20250818
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-21
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Require-Bundle: io.cloudbeaver.model,
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
<artifactId>io.cloudbeaver.service.rm.nio</artifactId>
|
||||
<version>1.0.43-SNAPSHOT</version>
|
||||
<version>1.0.45-SNAPSHOT</version>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2
|
||||
Bundle-Vendor: DBeaver Corp
|
||||
Bundle-Name: Cloudbeaver Web Service - Resource manager
|
||||
Bundle-SymbolicName: io.cloudbeaver.service.rm;singleton:=true
|
||||
Bundle-Version: 1.0.78.qualifier
|
||||
Bundle-Release-Date: 20250721
|
||||
Bundle-Version: 1.0.80.qualifier
|
||||
Bundle-Release-Date: 20250818
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-21
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Require-Bundle: io.cloudbeaver.server,
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
<artifactId>io.cloudbeaver.service.rm</artifactId>
|
||||
<version>1.0.78-SNAPSHOT</version>
|
||||
<version>1.0.80-SNAPSHOT</version>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2
|
||||
Bundle-Name: Cloudbeaver Web Service - Security
|
||||
Bundle-Vendor: DBeaver Corp
|
||||
Bundle-SymbolicName: io.cloudbeaver.service.security;singleton:=true
|
||||
Bundle-Version: 1.0.81.qualifier
|
||||
Bundle-Release-Date: 20250721
|
||||
Bundle-Version: 1.0.83.qualifier
|
||||
Bundle-Release-Date: 20250818
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-21
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Require-Bundle: org.jkiss.dbeaver.model;visibility:=reexport,
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
<artifactId>io.cloudbeaver.service.security</artifactId>
|
||||
<version>1.0.81-SNAPSHOT</version>
|
||||
<version>1.0.83-SNAPSHOT</version>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
|
||||
</project>
|
||||
|
||||
+23
-5
@@ -54,6 +54,7 @@ import org.jkiss.dbeaver.model.security.user.*;
|
||||
import org.jkiss.dbeaver.model.sql.SQLUtils;
|
||||
import org.jkiss.dbeaver.model.websocket.event.WSUserCloseSessionsEvent;
|
||||
import org.jkiss.dbeaver.model.websocket.event.WSUserDeletedEvent;
|
||||
import org.jkiss.dbeaver.model.websocket.event.WSUserDisabledEvent;
|
||||
import org.jkiss.dbeaver.model.websocket.event.permissions.WSObjectPermissionEvent;
|
||||
import org.jkiss.dbeaver.model.websocket.event.permissions.WSSubjectPermissionEvent;
|
||||
import org.jkiss.dbeaver.model.websocket.event.session.WSAuthEvent;
|
||||
@@ -411,7 +412,14 @@ public class CBEmbeddedSecurityController<T extends ServletAuthApplication>
|
||||
@NotNull Connection dbCon,
|
||||
@NotNull String userId,
|
||||
@NotNull String[] teamIds
|
||||
) throws SQLException {
|
||||
) throws SQLException, DBCException {
|
||||
String defaultTeam = getDefaultUserTeam();
|
||||
if (ArrayUtils.contains(teamIds, defaultTeam)) {
|
||||
throw new SMException("Cannot delete default user team: " + defaultTeam);
|
||||
}
|
||||
if (ArrayUtils.isEmpty(teamIds)) {
|
||||
return;
|
||||
}
|
||||
String deleteUserTeamsSql = "DELETE FROM {table_prefix}CB_USER_TEAM WHERE USER_ID=? " +
|
||||
"AND TEAM_ID IN (" + SQLUtils.generateParamList(teamIds.length) + ")";
|
||||
|
||||
@@ -819,6 +827,10 @@ public class CBEmbeddedSecurityController<T extends ServletAuthApplication>
|
||||
dbStat.setString(5, userId);
|
||||
dbStat.executeUpdate();
|
||||
}
|
||||
if (!enabled) {
|
||||
var event = new WSUserDisabledEvent(userId);
|
||||
application.getEventController().addEvent(event);
|
||||
}
|
||||
log.info(String.format("User updated: [userId=%s, isActive=%s, reason=%s]", userId, enabled, disableReason));
|
||||
}
|
||||
|
||||
@@ -1433,9 +1445,14 @@ public class CBEmbeddedSecurityController<T extends ServletAuthApplication>
|
||||
addSubjectPermissionsUpdateEvent(subjectId, null);
|
||||
}
|
||||
|
||||
|
||||
public void initialize() throws DBException {
|
||||
}
|
||||
|
||||
private void insertPermissions(Connection dbCon, String subjectId, String[] permissionIds, String grantorId) throws SQLException {
|
||||
if (!ArrayUtils.isEmpty(permissionIds)) {
|
||||
try (PreparedStatement dbStat = dbCon.prepareStatement(
|
||||
try (
|
||||
PreparedStatement dbStat = dbCon.prepareStatement(
|
||||
"INSERT INTO {table_prefix}CB_AUTH_PERMISSIONS" +
|
||||
"(SUBJECT_ID,PERMISSION_ID,GRANT_TIME,GRANTED_BY) VALUES(?,?,?,?)")
|
||||
) {
|
||||
@@ -1503,6 +1520,7 @@ public class CBEmbeddedSecurityController<T extends ServletAuthApplication>
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected Set<String> getUserPermissions(String userId, String authRole) throws DBException {
|
||||
return getUserPermissions(userId);
|
||||
}
|
||||
@@ -1584,7 +1602,7 @@ public class CBEmbeddedSecurityController<T extends ServletAuthApplication>
|
||||
}
|
||||
}
|
||||
|
||||
private Set<String> getAnonymousUserPermissions() throws DBException {
|
||||
protected Set<String> getAnonymousUserPermissions() throws DBException {
|
||||
var anonymousUserTeam = application.getAppConfiguration().getAnonymousUserTeam();
|
||||
return getSubjectPermissions(anonymousUserTeam);
|
||||
}
|
||||
@@ -2994,7 +3012,7 @@ public class CBEmbeddedSecurityController<T extends ServletAuthApplication>
|
||||
}
|
||||
|
||||
|
||||
private void addSubjectPermissionsUpdateEvent(@NotNull String subjectId, @Nullable SMSubjectType subjectType) {
|
||||
protected void addSubjectPermissionsUpdateEvent(@NotNull String subjectId, @Nullable SMSubjectType subjectType) {
|
||||
if (subjectType == null) {
|
||||
subjectType = getSubjectType(subjectId);
|
||||
}
|
||||
@@ -3408,7 +3426,7 @@ public class CBEmbeddedSecurityController<T extends ServletAuthApplication>
|
||||
}
|
||||
}
|
||||
|
||||
private SMSubjectType getSubjectType(@NotNull String subjectId) {
|
||||
protected SMSubjectType getSubjectType(@NotNull String subjectId) {
|
||||
try (Connection dbCon = database.openConnection()) {
|
||||
String sqlBuilder = "SELECT SUBJECT_TYPE FROM {table_prefix}CB_AUTH_SUBJECT U WHERE SUBJECT_ID = ?";
|
||||
try (var dbStat = dbCon.prepareStatement(sqlBuilder)) {
|
||||
|
||||
+8
-2
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2024 DBeaver Corp and others
|
||||
* Copyright (C) 2010-2025 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -46,7 +46,9 @@ public class EmbeddedSecurityControllerFactory<T extends ServletAuthApplication>
|
||||
SMCredentialsProvider credentialsProvider,
|
||||
SMControllerConfiguration smConfig
|
||||
) throws DBException {
|
||||
boolean initialization = false;
|
||||
if (DB_INSTANCE == null) {
|
||||
initialization = true;
|
||||
synchronized (EmbeddedSecurityControllerFactory.class) {
|
||||
if (DB_INSTANCE == null) {
|
||||
DB_INSTANCE = createAndInitDatabaseInstance(
|
||||
@@ -64,9 +66,13 @@ public class EmbeddedSecurityControllerFactory<T extends ServletAuthApplication>
|
||||
)).schedule();
|
||||
}
|
||||
}
|
||||
return createEmbeddedSecurityController(
|
||||
var controller = createEmbeddedSecurityController(
|
||||
application, DB_INSTANCE, credentialsProvider, smConfig
|
||||
);
|
||||
if (initialization) {
|
||||
controller.initialize();
|
||||
}
|
||||
return controller;
|
||||
}
|
||||
|
||||
protected @NotNull CBDatabase createAndInitDatabaseInstance(
|
||||
|
||||
+1
-1
@@ -24,7 +24,6 @@ import io.cloudbeaver.model.app.ServletApplication;
|
||||
import io.cloudbeaver.model.config.WebDatabaseConfig;
|
||||
import io.cloudbeaver.registry.WebAuthProviderDescriptor;
|
||||
import io.cloudbeaver.registry.WebAuthProviderRegistry;
|
||||
import org.jkiss.dbeaver.model.sql.db.InternalProxyConnection;
|
||||
import io.cloudbeaver.utils.ServletAppUtils;
|
||||
import org.apache.commons.dbcp2.*;
|
||||
import org.apache.commons.pool2.impl.GenericObjectPool;
|
||||
@@ -44,6 +43,7 @@ import org.jkiss.dbeaver.model.security.SMAdminController;
|
||||
import org.jkiss.dbeaver.model.security.user.SMTeam;
|
||||
import org.jkiss.dbeaver.model.security.user.SMUser;
|
||||
import org.jkiss.dbeaver.model.sql.db.InternalDB;
|
||||
import org.jkiss.dbeaver.model.sql.db.InternalProxyConnection;
|
||||
import org.jkiss.dbeaver.model.sql.schema.SQLSchemaConfig;
|
||||
import org.jkiss.dbeaver.registry.DataSourceProviderRegistry;
|
||||
import org.jkiss.dbeaver.registry.storage.H2Migrator;
|
||||
|
||||
@@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2
|
||||
Bundle-Vendor: DBeaver Corp
|
||||
Bundle-Name: CloudBeaver SLF4j Binding
|
||||
Bundle-SymbolicName: io.cloudbeaver.slf4j;singleton:=true
|
||||
Bundle-Version: 1.0.41.qualifier
|
||||
Bundle-Release-Date: 20250721
|
||||
Bundle-Version: 1.0.43.qualifier
|
||||
Bundle-Release-Date: 20250818
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-21
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Fragment-Host: slf4j.api
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
<artifactId>io.cloudbeaver.slf4j</artifactId>
|
||||
<version>1.0.41-SNAPSHOT</version>
|
||||
<version>1.0.43-SNAPSHOT</version>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
|
||||
</project>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user