Skip to content

Commit

Permalink
Merge branch 'devel' into CB-4441-maria-db-clear-auth-attempt-info-jo…
Browse files Browse the repository at this point in the history
…b-invalid-sql
  • Loading branch information
dariamarutkina authored Jan 22, 2024
2 parents 609f7fb + 76454a3 commit 0ed2670
Show file tree
Hide file tree
Showing 38 changed files with 273 additions and 135 deletions.
18 changes: 8 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,21 +22,19 @@ You can see live demo of CloudBeaver here: https://demo.cloudbeaver.io

## Changelog


### 23.3.2. 2024-01-22
- Added password policy for the local authorization. Password parameters can be set in the configuration file;
- The 'Keep alive' option has been added to the connection settings to keep the connection active even in case of inactivity;
- Added ability to display full text for a string data type in value panel;
- The DuckDB driver has been added;
- Different bug fixes and enhancements have been made.

### 23.3.2. 2024-01-08
- Added the ability to view decoded binary-type data in the Value panel;
- Enhanced security for unauthorized access;
- Different bug fixes and enhancements have been made.

### 23.3.1. 2023-12-25
- Performance:
- Upgraded to Jetty 11, delivering improved performance, enhanced features, and better alignment with the latest Java specifications.
- Resource management:
- Read-only scripts now have a padlock icon.
- UX improvement:
- Added validation for mandatory fields in all forms for creating and editing entities.
- Driver management:
- Apache Derby driver has been removed because of the vulnerability issues.
- Many small bug fixes, enhancements, and improvements have been made


### Old CloudBeaver releases
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,8 @@ List<SMUserProvisioning> listExternalUsers(
@NotNull SMAuthProviderCustomConfiguration customConfiguration,
@NotNull SMProvisioningFilter filter
) throws DBException;

default boolean isAuthRoleProvided(SMAuthProviderCustomConfiguration configuration) {
return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
import io.cloudbeaver.auth.CBAuthConstants;
import org.jkiss.dbeaver.DBException;

import java.util.List;

public interface WebAuthApplication extends WebApplication {
WebAuthConfiguration getAuthConfiguration();

Expand All @@ -30,4 +32,6 @@ default long getMaxSessionIdleTime() {
}

void flushConfiguration() throws DBException;

String getDefaultAuthRole();
}
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,12 @@ public boolean isPrivate() {
public boolean isRequired() {
return descriptor.isRequired();
}
public boolean isAuthRoleProvided(SMAuthProviderCustomConfiguration configuration) {
if (descriptor.getInstance() instanceof SMProvisioner provisioner) {
return provisioner.isAuthRoleProvided(configuration);
}
return false;
}

public boolean isSupportProvisioning() {
return descriptor.getInstance() instanceof SMProvisioner;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ type AuthProviderConfiguration {
id: ID!
displayName: String!
disabled: Boolean!
authRoleProvided: Boolean

iconURL: String
description: String
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ input DataTransferOutputSettingsInput {
encoding: String
timestampPattern: String
compress: Boolean
fileName: String
}

type DataTransferOutputSettings {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ public WebDataTransferDefaultExportSettings() {
false,
defConsumerSettings.getOutputEncoding(),
defConsumerSettings.getOutputTimestampPattern(),
defConsumerSettings.isCompressResults()
defConsumerSettings.isCompressResults(),
null
);
this.supportedEncodings = Charset.availableCharsets().keySet();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,22 @@ public class WebDataTransferOutputSettings {
private final String encoding;
private final String timestampPattern;
private final boolean compress;
private final String fileName;

public WebDataTransferOutputSettings(Map<String, Object> outputSettings) {
this.insertBom = JSONUtils.getBoolean(outputSettings, "insertBom", false);
this.encoding = JSONUtils.getString(outputSettings, "encoding");
this.timestampPattern = JSONUtils.getString(outputSettings, "timestampPattern");
this.compress = JSONUtils.getBoolean(outputSettings, "compress", false);
this.fileName = JSONUtils.getString(outputSettings, "fileName");
}

public WebDataTransferOutputSettings(boolean insertBom, String encoding, String timestampPattern, boolean compress) {
public WebDataTransferOutputSettings(boolean insertBom, String encoding, String timestampPattern, boolean compress, String fileName) {
this.insertBom = insertBom;
this.encoding = encoding;
this.timestampPattern = timestampPattern;
this.compress = compress;
this.fileName = fileName;
}

public boolean isInsertBom() {
Expand All @@ -55,4 +58,8 @@ public String getTimestampPattern() {
public boolean isCompress() {
return compress;
}

public String getFileName() {
return fileName;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -173,12 +173,15 @@ public void run(DBRProgressMonitor monitor) throws InvocationTargetException {
}
throw new DBException("Error exporting data", e);
}
Path finallyExportFile = parameters.getOutputSettings().isCompress()
var outputSettings = parameters.getOutputSettings();
Path finallyExportFile = outputSettings.isCompress()
? exportFile.resolveSibling(WebDataTransferUtils.normalizeFileName(
exportFile.getFileName().toString(), parameters.getOutputSettings()))
exportFile.getFileName().toString(), outputSettings))
: exportFile;
WebDataTransferTaskConfig taskConfig = new WebDataTransferTaskConfig(finallyExportFile, parameters);
String exportFileName = CommonUtils.escapeFileName(CommonUtils.truncateString(dataContainer.getName(), 32));
String exportFileName = CommonUtils.isEmpty(outputSettings.getFileName()) ?
CommonUtils.escapeFileName(CommonUtils.truncateString(dataContainer.getName(), 32)) :
outputSettings.getFileName();
taskConfig.setExportFileName(exportFileName);
WebDataTransferUtils.getSessionDataTransferConfig(sqlProcessor.getWebSession()).addTask(taskConfig);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,10 +133,6 @@ public void createUser(
try (Connection dbCon = database.openConnection()) {
try (JDBCTransaction txn = new JDBCTransaction(dbCon)) {
createUser(dbCon, userId, metaParameters, enabled, defaultAuthRole);
String defaultTeamName = application.getAppConfiguration().getDefaultUserTeam();
if (!CommonUtils.isEmpty(defaultTeamName)) {
setUserTeams(dbCon, userId, new String[]{defaultTeamName}, userId);
}
txn.commit();
}
} catch (SQLException e) {
Expand Down Expand Up @@ -167,31 +163,32 @@ public void createUser(
dbStat.execute();
}
saveSubjectMetas(dbCon, userId, metaParameters);

String defaultTeamName = application.getAppConfiguration().getDefaultUserTeam();
if (!CommonUtils.isEmpty(defaultTeamName)) {
setUserTeams(dbCon, userId, new String[]{defaultTeamName}, userId);
}
}

@Override
public void importUsers(@NotNull SMUserImportList userImportList) throws DBException {
for (SMUserProvisioning user : userImportList.getUsers()) {
if (isSubjectExists(user.getUserId())) {
log.info("Skip already exist user: " + user.getUserId());
setUserAuthRole(user.getUserId(), userImportList.getAuthRole());
continue;
}
createUser(user.getUserId(), user.getMetaParameters(), true, userImportList.getAuthRole());
}
try (var dbCon = database.openConnection()) {
importUsers(dbCon, userImportList);
} catch (SQLException e) {
log.error("Failed attempt import user: " + e.getMessage());
}
}

protected void importUsers(@NotNull Connection connection, @NotNull SMUserImportList userImportList)
throws DBException, SQLException {
for (SMUserProvisioning user : userImportList.getUsers()) {
String authRole = user.getAuthRole() == null ? userImportList.getAuthRole() : user.getAuthRole();
if (isSubjectExists(user.getUserId())) {
log.info("User already exist : " + user.getUserId());
setUserAuthRole(connection, user.getUserId(), userImportList.getAuthRole());
setUserAuthRole(connection, user.getUserId(), authRole);
enableUser(connection, user.getUserId(), true);
continue;
}
createUser(connection, user.getUserId(), user.getMetaParameters(), true, userImportList.getAuthRole());
createUser(connection, user.getUserId(), user.getMetaParameters(), true, authRole);
}
}

Expand Down
6 changes: 3 additions & 3 deletions webapp/packages/core-blocks/src/Icon.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,20 @@ import { Icon } from './Icon';
test('icons.svg#name', () => {
(globalThis as any)._ROOT_URI_ = undefined;

render(<Icon name="test" />);
render(<Icon data-testid="Icon" name="test" />);
expect(screen.getByTestId('Icon').querySelector('use')).toHaveAttribute('href', '/icons/icons.svg#test');
});

test('/image.jpg', () => {
(globalThis as any)._ROOT_URI_ = undefined;

render(<Icon name="/image.jpg" />);
render(<Icon data-testid="Icon" name="/image.jpg" />);
expect(screen.getByTestId('Icon').querySelector('use')).toHaveAttribute('href', '/image.jpg');
});

test('{_ROOT_URI_}/icons.svg#name', () => {
(globalThis as any)._ROOT_URI_ = '/path/';

render(<Icon name="test" />);
render(<Icon data-testid="Icon" name="test" />);
expect(screen.getByTestId('Icon').querySelector('use')).toHaveAttribute('href', '/path/icons/icons.svg#test');
});
11 changes: 10 additions & 1 deletion webapp/packages/core-blocks/src/Snackbars/ProcessSnackbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
* you may not use this file except in compliance with the License.
*/
import { observer } from 'mobx-react-lite';
import { useEffect, useState } from 'react';

import { ENotificationType, INotificationProcessExtraProps, NotificationComponent } from '@cloudbeaver/core-events';

Expand Down Expand Up @@ -35,7 +36,15 @@ export const ProcessSnackbar: NotificationComponent<ProcessSnackbarProps> = obse

const translate = useTranslate();
const details = useErrorDetails(error);
const displayed = useStateDelay(notification.state.deleteDelay === 0, displayDelay);
const [delayState, setDelayState] = useState(false);
const displayedReal = notification.state.deleteDelay === 0;
const displayed = useStateDelay(delayState, displayDelay);

useEffect(() => {
if (displayedReal) {
setDelayState(true);
}
}, [displayedReal]);

useActivationDelay(status === ENotificationType.Success, closeDelay, notification.close);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@

&.closing {
opacity: 0;
transform: translateX(-100%);
transition: opacity 0.5s ease-in-out, transform 0.5s ease-in-out;
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
.treeNodeIcon {
position: relative;
box-sizing: border-box;
pointer-events: none;
flex-shrink: 0;
width: 16px;
height: 16px;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import { useS } from '../../useS';
import style from './TreeNodeNested.m.css';

interface Props extends React.PropsWithChildren {
expanded?: boolean;
root?: boolean;
className?: string;
}
Expand Down
2 changes: 1 addition & 1 deletion webapp/packages/core-cli/configs/jest.babel.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@
*/
module.exports = {
presets: ['@babel/preset-env', ['@babel/preset-react', { runtime: 'automatic' }]],
plugins: ['../dist/babel-plugins/TestingAttributes.js', require('@reshadow/babel')],
plugins: [require('@reshadow/babel')],
};
5 changes: 4 additions & 1 deletion webapp/packages/core-cli/tests/test.environment.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,8 @@ module.exports = class CustomTestEnvironment extends Environment {
this.global.TextDecoder = TextDecoder;
this.global.Response = Response;
this.global.Request = Request;

// different machine has its own timezones and some tests can fail because of it
process.env.TZ = 'UTC';
}
};
};
1 change: 1 addition & 0 deletions webapp/packages/core-localization/src/locales/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ export default [
['ui_disable', 'Disable'],
['ui_readonly', 'Read-only'],
['ui_test', 'Test'],
['ui_export', 'Export'],

['root_permission_denied', "You don't have permissions"],
['root_permission_no_permission', "You don't have permission for this action"],
Expand Down
1 change: 1 addition & 0 deletions webapp/packages/core-localization/src/locales/it.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ export default [
['ui_disable', 'Disable'],
['ui_readonly', 'In sola lettura'],
['ui_test', 'Test'],
['ui_export', 'Export'],

['root_permission_denied', 'Non hai i permessi'],
['app_root_session_expire_warning_title', 'La sessione sta per scadere'],
Expand Down
1 change: 1 addition & 0 deletions webapp/packages/core-localization/src/locales/ru.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ export default [
['ui_disable', 'Отключить'],
['ui_readonly', 'Доступно только для чтения'],
['ui_test', 'Проверить'],
['ui_export', 'Экспорт'],

['root_permission_denied', 'Отказано в доступе'],
['root_permission_no_permission', 'У вас нет разрешения на это действие'],
Expand Down
1 change: 1 addition & 0 deletions webapp/packages/core-localization/src/locales/zh.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ export default [
['ui_disable', 'Disable'],
['ui_readonly', '只读'],
['ui_test', 'Test'],
['ui_export', 'Export'],

['root_permission_denied', '您没有权限'],
['root_permission_no_permission', '您没有权限执行此操作'],
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
fragment AuthProviderConfigurationInfo on AuthProviderConfiguration {
id
displayName
authRoleProvided
iconURL
description
signInLink
Expand Down
2 changes: 1 addition & 1 deletion webapp/packages/core-ui/src/DragAndDrop/useDNDData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ export function useDNDData(context: IDataContextProvider, options: IOptions = {}
}
}

state.isDragging = monitor.isDragging();
state.isDragging = dragging;
},
}));

Expand Down
Loading

0 comments on commit 0ed2670

Please sign in to comment.