From 12e1fb57d7b4be429b12de6d4a5077855291c06c Mon Sep 17 00:00:00 2001 From: Greg Miller Date: Tue, 17 Sep 2024 14:04:02 +0200 Subject: [PATCH 1/7] dbeaver/dbeaver-devops#1483 Added docker apt-get upgrade --- deploy/docker/cloudbeaver-ce/Dockerfile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/deploy/docker/cloudbeaver-ce/Dockerfile b/deploy/docker/cloudbeaver-ce/Dockerfile index 361df92c0a..4679467a03 100644 --- a/deploy/docker/cloudbeaver-ce/Dockerfile +++ b/deploy/docker/cloudbeaver-ce/Dockerfile @@ -2,6 +2,10 @@ FROM dbeaver/base-java MAINTAINER DBeaver Corp, devops@dbeaver.com +RUN set -eux; \ + apt-get update; \ + apt-get upgrade -y; + COPY cloudbeaver /opt/cloudbeaver EXPOSE 8978 From ea2246af31553478a538d2396232baf1cc2836e3 Mon Sep 17 00:00:00 2001 From: Greg Miller Date: Tue, 17 Sep 2024 14:09:01 +0200 Subject: [PATCH 2/7] dbeaver/dbeaver-devops#1483 Remove sed before apt-get --- deploy/docker/cloudbeaver-ce/Dockerfile | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/deploy/docker/cloudbeaver-ce/Dockerfile b/deploy/docker/cloudbeaver-ce/Dockerfile index 4679467a03..95bdcc6812 100644 --- a/deploy/docker/cloudbeaver-ce/Dockerfile +++ b/deploy/docker/cloudbeaver-ce/Dockerfile @@ -2,8 +2,7 @@ FROM dbeaver/base-java MAINTAINER DBeaver Corp, devops@dbeaver.com -RUN set -eux; \ - apt-get update; \ +RUN apt-get update; \ apt-get upgrade -y; COPY cloudbeaver /opt/cloudbeaver From 30e74ce09f24ae7133238c9e126dc9f032938bd6 Mon Sep 17 00:00:00 2001 From: alex <48489896+devnaumov@users.noreply.github.com> Date: Tue, 17 Sep 2024 15:44:44 +0200 Subject: [PATCH 3/7] CB-5450 purge cache if quota error happens (#2917) * CB-5450 purge cache if quota error happens * CB-5450 cache only images from the same origin * CB-5450 change window to self * CB-5450 revert purgeOnQuotaError --------- Co-authored-by: Evgenia Bezborodova <139753579+EvgeniaBzzz@users.noreply.github.com> --- webapp/packages/core-browser/src/service-worker.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/webapp/packages/core-browser/src/service-worker.ts b/webapp/packages/core-browser/src/service-worker.ts index 4849f1b029..2d104d07df 100644 --- a/webapp/packages/core-browser/src/service-worker.ts +++ b/webapp/packages/core-browser/src/service-worker.ts @@ -117,7 +117,7 @@ registerRoute( ); registerRoute( - ({ request }) => request.destination === 'image', + ({ request, url }) => url.origin === self.location.origin && request.destination === 'image', new CacheFirst({ cacheName: 'images', plugins: [ @@ -127,6 +127,7 @@ registerRoute( new ExpirationPlugin({ maxEntries: 1000, maxAgeSeconds: 7 * 24 * 60 * 60, + purgeOnQuotaError: true, }), ], }), From 5b527872bd7e70fd877b323004f85a281a5ca7d7 Mon Sep 17 00:00:00 2001 From: DenisSinelnikov <142215442+DenisSinelnikov@users.noreply.github.com> Date: Tue, 17 Sep 2024 20:30:19 +0400 Subject: [PATCH 4/7] CB-4095. Added env variables for configurations parameters (#2905) * CB-4095. Added env variables for configurations parameters * CB-4095. Refactor after review * CB-4095. Refactor after review, added sub group for envs * CB-4095. Remove unusable env variable --------- Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com> Co-authored-by: Alexander Skoblikov --- .../DefaultConfiguration/cloudbeaver.conf | 41 ++++++++-------- .../SQLiteConfiguration/cloudbeaver.conf | 39 ++++++++------- .../service/sql/WebSQLConstants.java | 1 - .../workspace/conf/cloudbeaver.conf | 47 +++++++++---------- 4 files changed, 62 insertions(+), 66 deletions(-) diff --git a/config/sample-databases/DefaultConfiguration/cloudbeaver.conf b/config/sample-databases/DefaultConfiguration/cloudbeaver.conf index 08112c854e..e063bf739b 100644 --- a/config/sample-databases/DefaultConfiguration/cloudbeaver.conf +++ b/config/sample-databases/DefaultConfiguration/cloudbeaver.conf @@ -1,8 +1,8 @@ { server: { - serverPort: 8978, + serverPort: "${CLOUDBEAVER_SERVICE_PORT:8978}", - workspaceLocation: "workspace", + workspaceLocation: "${CLOUDBEAVER_WORKSPACE_LOCATION:workspace}", contentRoot: "web", driversLocation: "drivers", @@ -27,9 +27,9 @@ sql.proposals.insert.table.alias: PLAIN }, - expireSessionAfterPeriod: 1800000, + expireSessionAfterPeriod: "${CLOUDBEAVER_EXPIRE_SESSION_AFTER_PERIOD:1800000}", - develMode: false, + develMode: "${CLOUDBEAVER_DEVEL_MODE:false}", enableSecurityManager: false, @@ -64,29 +64,28 @@ }, app: { - anonymousAccessEnabled: true, - anonymousUserRole: "user", - defaultUserTeam: "user", - grantConnectionsAccessToAnonymousTeam: false, - supportsCustomConnections: false, - showReadOnlyConnectionInfo: false, + anonymousAccessEnabled: "${CLOUDBEAVER_APP_ANONYMOUS_ACCESS_ENABLED:true}", + anonymousUserRole: user, + defaultUserTeam: "${CLOUDBEAVER_APP_DEFAULT_USER_TEAM:user}", + grantConnectionsAccessToAnonymousTeam: "${CLOUDBEAVER_APP_GRANT_CONNECTIONS_ACCESS_TO_ANONYMOUS_TEAM:false}", + supportsCustomConnections: "${CLOUDBEAVER_APP_SUPPORTS_CUSTOM_CONNECTIONS:false}", + showReadOnlyConnectionInfo: "${CLOUDBEAVER_APP_READ_ONLY_CONNECTION_INFO:false}", systemVariablesResolvingEnabled: "${CLOUDBEAVER_SYSTEM_VARIABLES_RESOLVING_ENABLED:false}", - forwardProxy: false, + forwardProxy: "${CLOUDBEAVER_APP_FORWARD_PROXY:false}", - publicCredentialsSaveEnabled: true, - adminCredentialsSaveEnabled: true, + publicCredentialsSaveEnabled: "${CLOUDBEAVER_APP_PUBLIC_CREDENTIALS_SAVE_ENABLED:true}", + adminCredentialsSaveEnabled: "${CLOUDBEAVER_APP_ADMIN_CREDENTIALS_SAVE_ENABLED:true}", - resourceManagerEnabled: true, + resourceManagerEnabled: "${CLOUDBEAVER_APP_RESOURCE_MANAGER_ENABLED:true}", resourceQuotas: { - dataExportFileSizeLimit: 10000000, - resourceManagerFileSizeLimit: 500000, - sqlMaxRunningQueries: 100, - sqlResultSetRowsLimit: 100000, - sqlResultSetMemoryLimit: 2000000, - sqlTextPreviewMaxLength: 4096, - sqlBinaryPreviewMaxLength: 261120 + dataExportFileSizeLimit: "${CLOUDBEAVER_RESOURCE_QUOTA_DATA_EXPORT_FILE_SIZE_LIMIT:10000000}", + resourceManagerFileSizeLimit: "${CLOUDBEAVER_RESOURCE_QUOTA_RESOURCE_MANAGER_FILE_SIZE_LIMIT:500000}", + sqlMaxRunningQueries: "${CLOUDBEAVER_RESOURCE_QUOTA_SQL_MAX_RUNNING_QUERIES:100}", + sqlResultSetRowsLimit: "${CLOUDBEAVER_RESOURCE_QUOTA_SQL_RESULT_SET_ROWS_LIMIT:100000}", + sqlTextPreviewMaxLength: "${CLOUDBEAVER_RESOURCE_QUOTA_SQL_TEXT_PREVIEW_MAX_LENGTH:4096}", + sqlBinaryPreviewMaxLength: "${CLOUDBEAVER_RESOURCE_QUOTA_SQL_BINARY_PREVIEW_MAX_LENGTH:261120}" }, enabledAuthProviders: [ "local" diff --git a/config/sample-databases/SQLiteConfiguration/cloudbeaver.conf b/config/sample-databases/SQLiteConfiguration/cloudbeaver.conf index efc8a5732f..3c96c0389e 100644 --- a/config/sample-databases/SQLiteConfiguration/cloudbeaver.conf +++ b/config/sample-databases/SQLiteConfiguration/cloudbeaver.conf @@ -1,8 +1,8 @@ { server: { - serverPort: 8978, + serverPort: "${CLOUDBEAVER_SERVICE_PORT:8978}", - workspaceLocation: "workspace", + workspaceLocation: "${CLOUDBEAVER_WORKSPACE_LOCATION:workspace}", contentRoot: "web", driversLocation: "drivers", @@ -25,9 +25,9 @@ sql.proposals.insert.table.alias: PLAIN }, - expireSessionAfterPeriod: 1800000, + expireSessionAfterPeriod: "${CLOUDBEAVER_EXPIRE_SESSION_AFTER_PERIOD:1800000}", - develMode: false, + develMode: "${CLOUDBEAVER_DEVEL_MODE:false}", enableSecurityManager: false, @@ -61,28 +61,27 @@ }, app: { - anonymousAccessEnabled: true, - anonymousUserRole: "user", - grantConnectionsAccessToAnonymousTeam: false, - supportsCustomConnections: false, - showReadOnlyConnectionInfo: false, + anonymousAccessEnabled: "${CLOUDBEAVER_APP_ANONYMOUS_ACCESS_ENABLED:true}", + anonymousUserRole: user, + grantConnectionsAccessToAnonymousTeam: "${CLOUDBEAVER_APP_GRANT_CONNECTIONS_ACCESS_TO_ANONYMOUS_TEAM:false}", + supportsCustomConnections: "${CLOUDBEAVER_APP_SUPPORTS_CUSTOM_CONNECTIONS:false}", + showReadOnlyConnectionInfo: "${CLOUDBEAVER_APP_READ_ONLY_CONNECTION_INFO:false}", systemVariablesResolvingEnabled: "${CLOUDBEAVER_SYSTEM_VARIABLES_RESOLVING_ENABLED:false}", - forwardProxy: false, + forwardProxy: "${CLOUDBEAVER_APP_FORWARD_PROXY:false}", - publicCredentialsSaveEnabled: true, - adminCredentialsSaveEnabled: true, + publicCredentialsSaveEnabled: "${CLOUDBEAVER_APP_PUBLIC_CREDENTIALS_SAVE_ENABLED:true}", + adminCredentialsSaveEnabled: "${CLOUDBEAVER_APP_ADMIN_CREDENTIALS_SAVE_ENABLED:true}", - resourceManagerEnabled: true, + resourceManagerEnabled: "${CLOUDBEAVER_APP_RESOURCE_MANAGER_ENABLED:true}", resourceQuotas: { - dataExportFileSizeLimit: 10000000, - resourceManagerFileSizeLimit: 500000, - sqlMaxRunningQueries: 100, - sqlResultSetRowsLimit: 100000, - sqlResultSetMemoryLimit: 2000000, - sqlTextPreviewMaxLength: 4096, - sqlBinaryPreviewMaxLength: 261120 + dataExportFileSizeLimit: "${CLOUDBEAVER_RESOURCE_QUOTA_DATA_EXPORT_FILE_SIZE_LIMIT:10000000}", + resourceManagerFileSizeLimit: "${CLOUDBEAVER_RESOURCE_QUOTA_RESOURCE_MANAGER_FILE_SIZE_LIMIT:500000}", + sqlMaxRunningQueries: "${CLOUDBEAVER_RESOURCE_QUOTA_SQL_MAX_RUNNING_QUERIES:100}", + sqlResultSetRowsLimit: "${CLOUDBEAVER_RESOURCE_QUOTA_SQL_RESULT_SET_ROWS_LIMIT:100000}", + sqlTextPreviewMaxLength: "${CLOUDBEAVER_RESOURCE_QUOTA_SQL_TEXT_PREVIEW_MAX_LENGTH:4096}", + sqlBinaryPreviewMaxLength: "${CLOUDBEAVER_RESOURCE_QUOTA_SQL_BINARY_PREVIEW_MAX_LENGTH:261120}" }, enabledAuthProviders: [ "local" diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/service/sql/WebSQLConstants.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/service/sql/WebSQLConstants.java index a8ff1bd845..561162394c 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/service/sql/WebSQLConstants.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/service/sql/WebSQLConstants.java @@ -22,7 +22,6 @@ public class WebSQLConstants { public static final String QUOTA_PROP_ROW_LIMIT = "sqlResultSetRowsLimit"; - public static final String QUOTA_PROP_MEMORY_LIMIT = "sqlResultSetMemoryLimit"; public static final String QUOTA_PROP_QUERY_LIMIT = "sqlMaxRunningQueries"; public static final String QUOTA_PROP_SQL_QUERY_TIMEOUT = "sqlQueryTimeout"; public static final String QUOTA_PROP_TEXT_PREVIEW_MAX_LENGTH = "sqlTextPreviewMaxLength"; diff --git a/server/test/io.cloudbeaver.test.platform/workspace/conf/cloudbeaver.conf b/server/test/io.cloudbeaver.test.platform/workspace/conf/cloudbeaver.conf index 6ba3e1b6ff..4511bd491c 100644 --- a/server/test/io.cloudbeaver.test.platform/workspace/conf/cloudbeaver.conf +++ b/server/test/io.cloudbeaver.test.platform/workspace/conf/cloudbeaver.conf @@ -1,9 +1,9 @@ { server: { serverPort: "${CLOUDBEAVER_TEST_PORT:18978}", - serverName: "CloudBeaver CE Test Server", + serverName: "${CLOUDBEAVER_SERVER_NAME:CloudBeaver CE Test Server}", - workspaceLocation: "workspace", + workspaceLocation: "${CLOUDBEAVER_WORKSPACE_LOCATION:workspace}", contentRoot: "workspace/web", driversLocation: "../../../deploy/", @@ -12,37 +12,37 @@ productSettings: {}, - expireSessionAfterPeriod: 1800000, + expireSessionAfterPeriod: "${CLOUDBEAVER_EXPIRE_SESSION_AFTER_PERIOD:1800000}", - develMode: false, + develMode: "${CLOUDBEAVER_DEVEL_MODE:false}", sm: { enableBruteForceProtection: "${CLOUDBEAVER_BRUTE_FORCE_PROTECTION_ENABLED:false}" }, database: { - driver="h2_embedded_v2", - url: "jdbc:h2:mem:testdb", + driver: "${CLOUDBEAVER_DB_DRIVER:h2_embedded_v2}", + url: "${CLOUDBEAVER_DB_URL:jdbc:h2:mem:testdb}", - createDatabase: true, + createDatabase: "${CLOUDBEAVER_CREATE_DATABASE:true}", - initialDataConfiguration: "workspace/conf/initial-data.conf", + initialDataConfiguration: "${CLOUDBEAVER_DB_INITIAL_DATA:workspace/conf/initial-data.conf}", pool: { - minIdleConnections: 4, - maxIdleConnections: 10, - maxConnections: 100, - validationQuery: "SELECT 1" + minIdleConnections: "${CLOUDBEAVER_DB_MIN_IDLE_CONNECTIONS:4}", + maxIdleConnections: "${CLOUDBEAVER_DB_MAX_IDLE_CONNECTIONS:10}", + maxConnections: "${CLOUDBEAVER_DB_MAX_CONNECTIONS:100}", + validationQuery: "${CLOUDBEAVER_DB_VALIDATION_QUERY:SELECT 1}" } } }, app: { - anonymousAccessEnabled: true, - anonymousUserRole: "user", - defaultUserTeam: "user", - supportsCustomConnections: true, - enableReverseProxyAuth: true, + anonymousAccessEnabled: "${CLOUDBEAVER_APP_ANONYMOUS_ACCESS_ENABLED:true}", + anonymousUserRole: user, + defaultUserTeam: "${CLOUDBEAVER_APP_DEFAULT_USER_TEAM:user}", + supportsCustomConnections: "${CLOUDBEAVER_APP_SUPPORTS_CUSTOM_CONNECTIONS:true}", + enableReverseProxyAuth: "${CLOUDBEAVER_APP_ENABLE_REVERSE_PROXY_AUTH:true}", enabledAuthProviders: [ "local", "reverseProxy" @@ -52,13 +52,12 @@ ], resourceQuotas: { - dataExportFileSizeLimit: 10000000, - sqlMaxRunningQueries: 100, - sqlResultSetRowsLimit: 100000, - sqlResultSetMemoryLimit: 2000000, - sqlTextPreviewMaxLength: 4096, - sqlBinaryPreviewMaxLength: 261120, - sqlQueryTimeout: 5 + dataExportFileSizeLimit: "${CLOUDBEAVER_RESOURCE_QUOTA_DATA_EXPORT_FILE_SIZE_LIMIT:10000000}", + sqlMaxRunningQueries: "${CLOUDBEAVER_RESOURCE_QUOTA_SQL_MAX_RUNNING_QUERIES:100}", + sqlResultSetRowsLimit: "${CLOUDBEAVER_RESOURCE_QUOTA_SQL_RESULT_SET_ROWS_LIMIT:100000}", + sqlTextPreviewMaxLength: "${CLOUDBEAVER_RESOURCE_QUOTA_SQL_TEXT_PREVIEW_MAX_LENGTH:4096}", + sqlBinaryPreviewMaxLength: "${CLOUDBEAVER_RESOURCE_QUOTA_SQL_BINARY_PREVIEW_MAX_LENGTH:261120}", + sqlQueryTimeout: "${CLOUDBEAVER_RESOURCE_QUOTA_SQL_QUERY_TIMEOUT:5}" }, disabledDrivers: [ From 4f0db5b854f634074893136bac31fcd7dc656014 Mon Sep 17 00:00:00 2001 From: Ainur <59531286+yagudin10@users.noreply.github.com> Date: Tue, 17 Sep 2024 18:50:04 +0200 Subject: [PATCH 5/7] CB-4896 migrate to jetty 12 (#2847) * CB-4896 migrate to jetty 12 * CB-4896 fix root uri * CB-4896 fix proxy handler paths * CB-4896 resolve conflicts * CB-4896 fix hidden gql errors * CB-4896 redirect welcome mode (redirect from '/' to index.html) * CB-4896 fix url 'blinking' --------- Co-authored-by: Alexander Skoblikov Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com> --- .../io.cloudbeaver.model/META-INF/MANIFEST.MF | 2 +- .../model/session/WebHttpRequestInfo.java | 57 ++++++ .../cloudbeaver/model/session/WebSession.java | 15 +- .../server/graphql/GraphQLEndpoint.java | 2 + .../server/jetty/CBJettyServer.java | 76 ++++---- .../server/jetty/CBJettyServletContext.java | 4 +- .../server/jetty/CBSessionHandler.java | 169 +++++++++++------- .../CBSymLinkContentAllowedAliasChecker.java | 38 ++++ .../server/servlets/CBStaticServlet.java | 59 +----- .../server/servlets/CBStatusServlet.java | 3 +- .../server/servlets/ProxyResourceHandler.java | 80 +++++++++ .../websockets/CBAbstractWebSocket.java | 24 +-- .../server/websockets/CBEventsWebSocket.java | 12 +- .../websockets/CBExpiredSessionWebSocket.java | 4 +- .../websockets/CBJettyWebSocketManager.java | 42 +++-- .../websockets/WebSocketPingPongCallback.java | 8 +- .../service/session/WebSessionManager.java | 41 +++-- .../service/sql/WebSQLFileLoaderServlet.java | 4 +- .../service/sql/WebSQLResultServlet.java | 30 +++- .../service/fs/model/WebFSServlet.java | 4 +- 20 files changed, 430 insertions(+), 244 deletions(-) create mode 100644 server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebHttpRequestInfo.java create mode 100644 server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/jetty/CBSymLinkContentAllowedAliasChecker.java create mode 100644 server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/servlets/ProxyResourceHandler.java diff --git a/server/bundles/io.cloudbeaver.model/META-INF/MANIFEST.MF b/server/bundles/io.cloudbeaver.model/META-INF/MANIFEST.MF index 6a557347eb..b1a8d173c5 100644 --- a/server/bundles/io.cloudbeaver.model/META-INF/MANIFEST.MF +++ b/server/bundles/io.cloudbeaver.model/META-INF/MANIFEST.MF @@ -19,7 +19,7 @@ Require-Bundle: org.jkiss.dbeaver.data.gis;visibility:=reexport, org.jkiss.bundle.graphql.java;visibility:=reexport, org.jkiss.bundle.apache.dbcp, com.google.gson;visibility:=reexport, - jakarta.servlet;visibility:=reexport + jakarta.servlet-api;bundle-version:="6.0.0";visibility:=reexport Export-Package: io.cloudbeaver, io.cloudbeaver.auth, io.cloudbeaver.auth.provider, diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebHttpRequestInfo.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebHttpRequestInfo.java new file mode 100644 index 0000000000..a6dde6469d --- /dev/null +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebHttpRequestInfo.java @@ -0,0 +1,57 @@ +/* + * DBeaver - Universal Database Manager + * Copyright (C) 2010-2024 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.model.session; + +import jakarta.servlet.http.HttpServletRequest; + +public class WebHttpRequestInfo { + + private final String id; + private final Object locale; + private final String lastRemoteAddress; + private final String lastRemoteUserAgent; + + public WebHttpRequestInfo(HttpServletRequest request) { + this.id = request.getSession().getId(); + this.locale = request.getAttribute("locale"); + this.lastRemoteAddress = request.getRemoteAddr(); + this.lastRemoteUserAgent = request.getHeader("User-Agent"); + } + + public WebHttpRequestInfo(String id, Object locale, String lastRemoteAddress, String lastRemoteUserAgent) { + this.id = id; + this.locale = locale; + this.lastRemoteAddress = lastRemoteAddress; + this.lastRemoteUserAgent = lastRemoteUserAgent; + } + + public String getId() { + return id; + } + + public Object getLocale() { + return locale; + } + + public String getLastRemoteAddress() { + return lastRemoteAddress; + } + + public String getLastRemoteUserAgent() { + return lastRemoteUserAgent; + } +} diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebSession.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebSession.java index 5b1d052433..bf0bc809c9 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebSession.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebSession.java @@ -33,7 +33,6 @@ import io.cloudbeaver.utils.CBModelConstants; import io.cloudbeaver.utils.WebAppUtils; import io.cloudbeaver.utils.WebDataSourceUtils; -import jakarta.servlet.http.HttpServletRequest; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; @@ -124,13 +123,13 @@ public class WebSession extends BaseWebSession private final Map sessionHandlers; public WebSession( - @NotNull HttpServletRequest request, + @NotNull WebHttpRequestInfo requestInfo, @NotNull WebAuthApplication application, @NotNull Map sessionHandlers ) throws DBException { - super(request.getSession().getId(), application); + super(requestInfo.getId(), application); this.lastAccessTime = this.createTime; - setLocale(CommonUtils.toString(request.getSession().getAttribute(ATTR_LOCALE), this.locale)); + setLocale(CommonUtils.toString(requestInfo.getLocale(), this.locale)); this.sessionHandlers = sessionHandlers; //force authorization of anonymous session to avoid access error, //because before authorization could be called by any request, @@ -138,7 +137,7 @@ public WebSession( //and the order of requests is not guaranteed. //look at CB-4747 refreshSessionAuth(); - updateSessionParameters(request); + updateSessionParameters(requestInfo); } @Nullable @@ -558,9 +557,9 @@ public synchronized void updateInfo(boolean isOldHttpSessionUsed) { } } - public synchronized void updateSessionParameters(HttpServletRequest request) { - this.lastRemoteAddr = request.getRemoteAddr(); - this.lastRemoteUserAgent = request.getHeader("User-Agent"); + public synchronized void updateSessionParameters(WebHttpRequestInfo requestInfo) { + this.lastRemoteAddr = requestInfo.getLastRemoteAddress(); + this.lastRemoteUserAgent = requestInfo.getLastRemoteUserAgent(); this.cacheExpired = false; } diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/graphql/GraphQLEndpoint.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/graphql/GraphQLEndpoint.java index a0ee694bae..c3d9bf0f91 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/graphql/GraphQLEndpoint.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/graphql/GraphQLEndpoint.java @@ -23,6 +23,7 @@ import graphql.language.SourceLocation; import graphql.schema.DataFetchingEnvironment; import graphql.schema.GraphQLSchema; +import graphql.schema.PropertyDataFetcherHelper; import graphql.schema.idl.SchemaGenerator; import graphql.schema.idl.SchemaParser; import graphql.schema.idl.TypeDefinitionRegistry; @@ -77,6 +78,7 @@ public class GraphQLEndpoint extends HttpServlet { public GraphQLEndpoint() { GraphQLSchema schema = buildSchema(); + PropertyDataFetcherHelper.setUseLambdaFactory(false); graphQL = GraphQL .newGraphQL(schema) .instrumentation(new SimplePerformantInstrumentation()) diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/jetty/CBJettyServer.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/jetty/CBJettyServer.java index f30a4a1e46..ddf67a7d43 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/jetty/CBJettyServer.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/jetty/CBJettyServer.java @@ -23,18 +23,16 @@ import io.cloudbeaver.server.servlets.CBImageServlet; import io.cloudbeaver.server.servlets.CBStaticServlet; import io.cloudbeaver.server.servlets.CBStatusServlet; +import io.cloudbeaver.server.servlets.ProxyResourceHandler; import io.cloudbeaver.server.websockets.CBJettyWebSocketManager; import io.cloudbeaver.service.DBWServiceBindingServlet; +import org.eclipse.jetty.ee10.servlet.*; import org.eclipse.jetty.server.*; -import org.eclipse.jetty.server.session.DefaultSessionCache; -import org.eclipse.jetty.server.session.DefaultSessionIdManager; -import org.eclipse.jetty.server.session.NullSessionDataStore; -import org.eclipse.jetty.servlet.ErrorPageErrorHandler; -import org.eclipse.jetty.servlet.ServletContextHandler; -import org.eclipse.jetty.servlet.ServletHolder; -import org.eclipse.jetty.servlet.ServletMapping; -import org.eclipse.jetty.util.resource.PathResource; -import org.eclipse.jetty.websocket.server.config.JettyWebSocketServletContainerInitializer; +import org.eclipse.jetty.session.DefaultSessionCache; +import org.eclipse.jetty.session.DefaultSessionIdManager; +import org.eclipse.jetty.session.NullSessionDataStore; +import org.eclipse.jetty.util.resource.ResourceFactory; +import org.eclipse.jetty.websocket.server.WebSocketUpgradeHandler; import org.eclipse.jetty.xml.XmlConfiguration; import org.jkiss.code.NotNull; import org.jkiss.code.Nullable; @@ -66,15 +64,15 @@ public CBJettyServer(@NotNull CBApplication application) { public void runServer() { try { CBServerConfig serverConfiguration = application.getServerConfiguration(); - JettyServer server; + Server server; int serverPort = serverConfiguration.getServerPort(); String serverHost = serverConfiguration.getServerHost(); Path sslPath = getSslConfigurationPath(); boolean sslConfigurationExists = sslPath != null && Files.exists(sslPath); if (sslConfigurationExists) { - server = new JettyServer(); - XmlConfiguration sslConfiguration = new XmlConfiguration(new PathResource(sslPath)); + server = new Server(); + XmlConfiguration sslConfiguration = new XmlConfiguration(ResourceFactory.of(server).newResource(sslPath)); ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); // method sslConfiguration.configure() does not see the context class of the Loader, // so we have to configure it manually, then return the old classLoader. @@ -83,23 +81,30 @@ public void runServer() { Thread.currentThread().setContextClassLoader(classLoader); } else { if (CommonUtils.isEmpty(serverHost)) { - server = new JettyServer(serverPort); + server = new Server(serverPort); } else { - server = new JettyServer( + server = new Server( InetSocketAddress.createUnresolved(serverHost, serverPort)); } } { // Handler configuration + Path contentRootPath = Path.of(serverConfiguration.getContentRoot()); ServletContextHandler servletContextHandler = new ServletContextHandler(ServletContextHandler.SESSIONS); - servletContextHandler.setResourceBase(serverConfiguration.getContentRoot()); + servletContextHandler.setBaseResourceAsPath(contentRootPath); String rootURI = serverConfiguration.getRootURI(); servletContextHandler.setContextPath(rootURI); ServletHolder staticServletHolder = new ServletHolder("static", new CBStaticServlet()); staticServletHolder.setInitParameter("dirAllowed", "false"); - servletContextHandler.addServlet(staticServletHolder, "/*"); + staticServletHolder.setInitParameter("cacheControl", "public, max-age=" + CBStaticServlet.STATIC_CACHE_SECONDS); + servletContextHandler.addServlet(staticServletHolder, "/"); + servletContextHandler.insertHandler(new ProxyResourceHandler(Path.of(serverConfiguration.getContentRoot()))); + + if (Files.isSymbolicLink(contentRootPath)) { + servletContextHandler.addAliasCheck(new CBSymLinkContentAllowedAliasChecker(contentRootPath)); + } ServletHolder imagesServletHolder = new ServletHolder("images", new CBImageServlet()); servletContextHandler.addServlet(imagesServletHolder, serverConfiguration.getServicesURI() + "images/*"); @@ -120,12 +125,7 @@ public void runServer() { } } - initSessionManager(this.application, servletContextHandler); - - server.setHandler(servletContextHandler); - - JettyWebSocketServletContainerInitializer.configure(servletContextHandler, - (context, wsContainer) -> { + WebSocketUpgradeHandler webSocketHandler = WebSocketUpgradeHandler.from(server, servletContextHandler, (wsContainer) -> { wsContainer.setIdleTimeout(Duration.ofMinutes(5)); // Add websockets wsContainer.addMapping( @@ -134,6 +134,12 @@ public void runServer() { ); } ); + servletContextHandler.insertHandler(webSocketHandler); + + initSessionManager(this.application, server, servletContextHandler); + + server.setHandler(servletContextHandler); + ErrorPageErrorHandler errorHandler = new ErrorPageErrorHandler(); //errorHandler.addErrorPage(404, "/missing.html"); servletContextHandler.setErrorHandler(errorHandler); @@ -180,10 +186,11 @@ private Path getSslConfigurationPath() { private void initSessionManager( @NotNull CBApplication application, + @NotNull Server server, @NotNull ServletContextHandler servletContextHandler ) { // Init sessions persistence - CBSessionHandler sessionHandler = new CBSessionHandler(application); + SessionHandler sessionHandler = new SessionHandler(); var maxIdleTime = application.getMaxSessionIdleTime(); int intMaxIdleSeconds; if (maxIdleTime > Integer.MAX_VALUE) { @@ -198,27 +205,10 @@ private void initSessionManager( sessionCache.setSessionDataStore(new NullSessionDataStore()); sessionHandler.setSessionCache(sessionCache); servletContextHandler.setSessionHandler(sessionHandler); - } - - public static class JettyServer extends Server { - public JettyServer(int serverPort) { - super(serverPort); - } - public JettyServer() { - super(); - } - public JettyServer(InetSocketAddress addr) { - super(addr); - } + DefaultSessionIdManager idMgr = new DefaultSessionIdManager(server); + idMgr.setWorkerName(null); + server.addBean(idMgr, true); - @Override - public void setSessionIdManager(SessionIdManager sessionIdManager) { - if (sessionIdManager instanceof DefaultSessionIdManager) { - // Nullify worker name to avoid dummy prefixes in session ID cookie - ((DefaultSessionIdManager) sessionIdManager).setWorkerName(null); - } - super.setSessionIdManager(sessionIdManager); - } } } \ No newline at end of file diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/jetty/CBJettyServletContext.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/jetty/CBJettyServletContext.java index 0579ff22b0..b04374442c 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/jetty/CBJettyServletContext.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/jetty/CBJettyServletContext.java @@ -19,8 +19,8 @@ import io.cloudbeaver.service.DBWServletContext; import jakarta.servlet.http.HttpServlet; -import org.eclipse.jetty.servlet.ServletContextHandler; -import org.eclipse.jetty.servlet.ServletHolder; +import org.eclipse.jetty.ee10.servlet.ServletContextHandler; +import org.eclipse.jetty.ee10.servlet.ServletHolder; public class CBJettyServletContext implements DBWServletContext { private final ServletContextHandler contextHandler; diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/jetty/CBSessionHandler.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/jetty/CBSessionHandler.java index 6a091573c2..907c9e3758 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/jetty/CBSessionHandler.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/jetty/CBSessionHandler.java @@ -18,8 +18,13 @@ import io.cloudbeaver.server.CBApplication; import jakarta.servlet.SessionCookieConfig; -import org.eclipse.jetty.http.Syntax; -import org.eclipse.jetty.server.session.SessionHandler; +import org.eclipse.jetty.ee10.servlet.ServletContextHandler; +import org.eclipse.jetty.ee10.servlet.SessionHandler; + +import java.util.Collections; +import java.util.Locale; +import java.util.Map; +import java.util.TreeMap; public class CBSessionHandler extends SessionHandler { private final CBCookieConfig cbCookieConfig; @@ -37,107 +42,147 @@ public SessionCookieConfig getSessionCookieConfig() { } - //mostly copy of org.eclipse.jetty.server.session.CookieConfig but allows to use dynamic setSecure flag + //mostly copy of org.eclipse.jetty.ee10.servlet.CookieConfig but allows to use dynamic setSecure flag public final class CBCookieConfig implements SessionCookieConfig { - public CBCookieConfig() { + + @Override + public boolean isSecure() { + var serverUrl = CBSessionHandler.this.application.getServerURL(); + return serverUrl != null && serverUrl.startsWith("https://"); } + @Override public String getComment() { - return CBSessionHandler.this._sessionComment; + return getSessionComment(); } + @Override public String getDomain() { - return CBSessionHandler.this._sessionDomain; + return getSessionDomain(); } + @Override public int getMaxAge() { - return CBSessionHandler.this._maxCookieAge; + return getMaxCookieAge(); } + @Override + public void setAttribute(String name, String value) { + checkState(); + String lcase = name.toLowerCase(Locale.ENGLISH); + + switch (lcase) { + case "name" -> setName(value); + case "max-age" -> setMaxAge(value == null ? -1 : Integer.parseInt(value)); + case "comment" -> setComment(value); + case "domain" -> setDomain(value); + case "httponly" -> setHttpOnly(Boolean.parseBoolean(value)); + case "secure" -> setSecure(Boolean.parseBoolean(value)); + case "path" -> setPath(value); + default -> setSessionCookieAttribute(name, value); + } + } + + @Override + public String getAttribute(String name) { + String lcase = name.toLowerCase(Locale.ENGLISH); + return switch (lcase) { + case "name" -> getName(); + case "max-age" -> Integer.toString(getMaxAge()); + case "comment" -> getComment(); + case "domain" -> getDomain(); + case "httponly" -> String.valueOf(isHttpOnly()); + case "secure" -> String.valueOf(isSecure()); + case "path" -> getPath(); + default -> getSessionCookieAttribute(name); + }; + } + + /** + * According to the SessionCookieConfig javadoc, the attributes must also include + * all values set by explicit setters. + * + * @see SessionCookieConfig + */ + @Override + public Map getAttributes() { + Map specials = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); + specials.put("name", getAttribute("name")); + specials.put("max-age", getAttribute("max-age")); + specials.put("comment", getAttribute("comment")); + specials.put("domain", getAttribute("domain")); + specials.put("httponly", getAttribute("httponly")); + specials.put("secure", getAttribute("secure")); + specials.put("path", getAttribute("path")); + specials.putAll(getSessionCookieAttributes()); + return Collections.unmodifiableMap(specials); + } + + @Override public String getName() { - return CBSessionHandler.this._sessionCookie; + return getSessionCookie(); } + @Override public String getPath() { - return CBSessionHandler.this._sessionPath; + return getSessionPath(); } + @Override public boolean isHttpOnly() { - return CBSessionHandler.this._httpOnly; - } - - public boolean isSecure() { - var serverUrl = CBSessionHandler.this.application.getServerURL(); - return serverUrl != null && serverUrl.startsWith("https://"); + return CBSessionHandler.this.isHttpOnly(); } + @Override public void setComment(String comment) { - if (CBSessionHandler.this._context != null && CBSessionHandler.this._context.getContextHandler() - .isAvailable()) { - throw new IllegalStateException("CookieConfig cannot be set after ServletContext is started"); - } else { - CBSessionHandler.this._sessionComment = comment; - } + checkState(); + CBSessionHandler.this.setSessionComment(comment); } + @Override public void setDomain(String domain) { - if (CBSessionHandler.this._context != null && CBSessionHandler.this._context.getContextHandler() - .isAvailable()) { - throw new IllegalStateException("CookieConfig cannot be set after ServletContext is started"); - } else { - CBSessionHandler.this._sessionDomain = domain; - } + checkState(); + CBSessionHandler.this.setSessionDomain(domain); } + @Override public void setHttpOnly(boolean httpOnly) { - if (CBSessionHandler.this._context != null && CBSessionHandler.this._context.getContextHandler() - .isAvailable()) { - throw new IllegalStateException("CookieConfig cannot be set after ServletContext is started"); - } else { - CBSessionHandler.this._httpOnly = httpOnly; - } + checkState(); + CBSessionHandler.this.setHttpOnly(httpOnly); } + @Override public void setMaxAge(int maxAge) { - if (CBSessionHandler.this._context != null && CBSessionHandler.this._context.getContextHandler() - .isAvailable()) { - throw new IllegalStateException("CookieConfig cannot be set after ServletContext is started"); - } else { - CBSessionHandler.this._maxCookieAge = maxAge; - } + checkState(); + CBSessionHandler.this.setMaxCookieAge(maxAge); } + @Override public void setName(String name) { - if (CBSessionHandler.this._context != null && CBSessionHandler.this._context.getContextHandler() - .isAvailable()) { - throw new IllegalStateException("CookieConfig cannot be set after ServletContext is started"); - } else if ("".equals(name)) { - throw new IllegalArgumentException("Blank cookie name"); - } else { - if (name != null) { - Syntax.requireValidRFC2616Token(name, "Bad Session cookie name"); - } - - CBSessionHandler.this._sessionCookie = name; - } + checkState(); + CBSessionHandler.this.setSessionCookie(name); } + @Override public void setPath(String path) { - if (CBSessionHandler.this._context != null && CBSessionHandler.this._context.getContextHandler() - .isAvailable()) { - throw new IllegalStateException("CookieConfig cannot be set after ServletContext is started"); - } else { - CBSessionHandler.this._sessionPath = path; - } + checkState(); + CBSessionHandler.this.setSessionPath(path); } + @Override public void setSecure(boolean secure) { - if (CBSessionHandler.this._context != null && CBSessionHandler.this._context.getContextHandler() - .isAvailable()) { + checkState(); + CBSessionHandler.this.setSecureCookies(secure); + } + + private void checkState() { + //It is allowable to call the CookieConfig.setXX methods after the SessionHandler has started, + //but before the context has fully started. Ie it is allowable for ServletContextListeners + //to call these methods in contextInitialized(). + ServletContextHandler handler = ServletContextHandler.getCurrentServletContextHandler(); + if (handler != null && handler.isAvailable()) throw new IllegalStateException("CookieConfig cannot be set after ServletContext is started"); - } else { - CBSessionHandler.this._secureCookies = secure; - } + } } diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/jetty/CBSymLinkContentAllowedAliasChecker.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/jetty/CBSymLinkContentAllowedAliasChecker.java new file mode 100644 index 0000000000..ecfc108878 --- /dev/null +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/jetty/CBSymLinkContentAllowedAliasChecker.java @@ -0,0 +1,38 @@ +/* + * DBeaver - Universal Database Manager + * Copyright (C) 2010-2024 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 org.eclipse.jetty.server.AliasCheck; +import org.eclipse.jetty.util.resource.Resource; +import org.jkiss.code.NotNull; + +import java.nio.file.Path; + +public class CBSymLinkContentAllowedAliasChecker implements AliasCheck { + @NotNull + private final Path contentRootPath; + + public CBSymLinkContentAllowedAliasChecker(@NotNull Path contentRootPath) { + this.contentRootPath = contentRootPath; + } + + @Override + public boolean checkAlias(String pathInContext, Resource resource) { + Path resourcePath = resource.getPath(); + return resourcePath != null && resourcePath.startsWith(contentRootPath); + } +} diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/servlets/CBStaticServlet.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/servlets/CBStaticServlet.java index 11ad45034e..b191027991 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/servlets/CBStaticServlet.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/servlets/CBStaticServlet.java @@ -29,28 +29,19 @@ import io.cloudbeaver.server.CBAppConfig; import io.cloudbeaver.server.CBApplication; import io.cloudbeaver.server.CBPlatform; -import io.cloudbeaver.server.CBServerConfig; import jakarta.servlet.ServletException; import jakarta.servlet.annotation.WebServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; -import org.eclipse.jetty.http.HttpContent; -import org.eclipse.jetty.http.HttpField; -import org.eclipse.jetty.http.HttpHeader; -import org.eclipse.jetty.server.ResourceService; -import org.eclipse.jetty.servlet.DefaultServlet; -import org.eclipse.jetty.util.resource.Resource; +import org.eclipse.jetty.ee10.servlet.DefaultServlet; import org.jkiss.dbeaver.DBException; import org.jkiss.dbeaver.Log; import org.jkiss.dbeaver.model.auth.SMAuthInfo; import org.jkiss.dbeaver.model.auth.SMAuthProvider; import org.jkiss.dbeaver.model.security.SMAuthProviderCustomConfiguration; import org.jkiss.utils.CommonUtils; -import org.jkiss.utils.IOUtils; -import java.io.*; -import java.nio.charset.StandardCharsets; -import java.util.Enumeration; +import java.io.IOException; import java.util.Map; @WebServlet(urlPatterns = "/") @@ -62,10 +53,6 @@ public class CBStaticServlet extends DefaultServlet { private static final Log log = Log.getLog(CBStaticServlet.class); - public CBStaticServlet() { - super(makeResourceService()); - } - @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { for (WebServletHandlerDescriptor handler : WebHandlerRegistry.getInstance().getServletHandlers()) { @@ -189,46 +176,4 @@ private boolean processSessionStart(HttpServletRequest request, HttpServletRespo return false; } - private static ResourceService makeResourceService() { - ResourceService resourceService = new ProxyResourceService(); - resourceService.setCacheControl(new HttpField(HttpHeader.CACHE_CONTROL, "public, max-age=" + STATIC_CACHE_SECONDS)); - return resourceService; - } - - - private static class ProxyResourceService extends ResourceService { - @Override - protected boolean sendData(HttpServletRequest request, HttpServletResponse response, boolean include, HttpContent content, Enumeration reqRanges) throws IOException { - String resourceName = content.getResource().getName(); - if (resourceName.endsWith("index.html") || resourceName.endsWith("sso.html")) { - return patchIndexHtml(response, content); - } - return super.sendData(request, response, include, content, reqRanges); - } - - private boolean patchIndexHtml(HttpServletResponse response, HttpContent content) throws IOException { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - Resource resource = content.getResource(); - File file = resource.getFile(); - try (InputStream fis = new FileInputStream(file)) { - IOUtils.copyStream(fis, baos); - } - String indexContents = baos.toString(StandardCharsets.UTF_8); - CBServerConfig serverConfig = CBApplication.getInstance().getServerConfiguration(); - indexContents = indexContents - .replace("{ROOT_URI}", serverConfig.getRootURI()) - .replace("{STATIC_CONTENT}", serverConfig.getStaticContent()); - byte[] indexBytes = indexContents.getBytes(StandardCharsets.UTF_8); - - putHeaders(response, content, indexBytes.length); - // Disable cache for index.html - response.setHeader(HttpHeader.CACHE_CONTROL.toString(), "no-cache, no-store, must-revalidate"); - response.setHeader(HttpHeader.EXPIRES.toString(), "0"); - - response.getOutputStream().write(indexBytes); - - return true; - } - } - } \ No newline at end of file diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/servlets/CBStatusServlet.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/servlets/CBStatusServlet.java index ceb4fdf748..53979a462c 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/servlets/CBStatusServlet.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/servlets/CBStatusServlet.java @@ -23,8 +23,7 @@ import jakarta.servlet.annotation.WebServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; -import org.eclipse.jetty.servlet.DefaultServlet; -import org.jkiss.dbeaver.DBException; +import org.eclipse.jetty.ee10.servlet.DefaultServlet; import org.jkiss.dbeaver.Log; import org.jkiss.dbeaver.model.data.json.JSONUtils; import org.jkiss.dbeaver.utils.GeneralUtils; diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/servlets/ProxyResourceHandler.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/servlets/ProxyResourceHandler.java new file mode 100644 index 0000000000..12b89242f5 --- /dev/null +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/servlets/ProxyResourceHandler.java @@ -0,0 +1,80 @@ +/* + * DBeaver - Universal Database Manager + * Copyright (C) 2010-2024 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.servlets; + +import io.cloudbeaver.server.CBApplication; +import io.cloudbeaver.server.CBServerConfig; +import org.eclipse.jetty.http.HttpHeader; +import org.eclipse.jetty.server.Handler; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.Response; +import org.eclipse.jetty.util.Callback; +import org.jkiss.code.NotNull; +import org.jkiss.utils.IOUtils; + +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; + +public class ProxyResourceHandler extends Handler.Wrapper { + @NotNull + private final Path contentRoot; + + public ProxyResourceHandler(@NotNull Path contentRoot) { + this.contentRoot = contentRoot; + } + + public boolean handle(Request request, Response response, Callback callback) throws Exception { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + String pathInContext = Request.getPathInContext(request); + + if ("/".equals(pathInContext)) { + pathInContext = "index.html"; + } + + if (pathInContext == null || !pathInContext.endsWith("index.html") + && !pathInContext.endsWith("sso.html") + && !pathInContext.endsWith("ssoError.html") + ) { + return super.handle(request, response, callback); + } + + if (pathInContext.startsWith("/")) { + pathInContext = pathInContext.substring(1); + } + var filePath = contentRoot.resolve(pathInContext); + try (InputStream fis = Files.newInputStream(filePath)) { + IOUtils.copyStream(fis, baos); + } + String indexContents = baos.toString(StandardCharsets.UTF_8); + CBServerConfig serverConfig = CBApplication.getInstance().getServerConfiguration(); + indexContents = indexContents + .replace("{ROOT_URI}", serverConfig.getRootURI()) + .replace("{STATIC_CONTENT}", serverConfig.getStaticContent()); + byte[] indexBytes = indexContents.getBytes(StandardCharsets.UTF_8); + + // Disable cache for index.html + response.getHeaders().put(HttpHeader.CACHE_CONTROL.toString(), "no-cache, no-store, must-revalidate"); + response.getHeaders().put(HttpHeader.EXPIRES.toString(), "0"); + + response.write(true, ByteBuffer.wrap(indexBytes), callback); + return true; + } +} diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/websockets/CBAbstractWebSocket.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/websockets/CBAbstractWebSocket.java index 807814ea19..2dac868a86 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/websockets/CBAbstractWebSocket.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/websockets/CBAbstractWebSocket.java @@ -17,29 +17,31 @@ package io.cloudbeaver.server.websockets; import com.google.gson.Gson; -import org.eclipse.jetty.websocket.api.WebSocketAdapter; +import org.eclipse.jetty.websocket.api.Callback; +import org.eclipse.jetty.websocket.api.Session; import org.jkiss.dbeaver.Log; import org.jkiss.dbeaver.model.websocket.WSUtils; import org.jkiss.dbeaver.model.websocket.event.WSEvent; -import java.io.IOException; - -public class CBAbstractWebSocket extends WebSocketAdapter { +public class CBAbstractWebSocket extends Session.Listener.AbstractAutoDemanding { private static final Log log = Log.getLog(CBAbstractWebSocket.class); protected static final Gson gson = WSUtils.gson; public void handleEvent(WSEvent event) { - if (isNotConnected()) { + if (!isOpen()) { return; } - try { - getRemote().sendString(gson.toJson(event)); - } catch (IOException e) { - handleEventException(e); - } + Session session = getSession(); + session.sendText(gson.toJson(event), new Callback() { + @Override + public void fail(Throwable e) { + handleEventException(e); + } + }); + } - protected void handleEventException(Exception e) { + protected void handleEventException(Throwable e) { log.error("Failed to send websocket message", e); } diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/websockets/CBEventsWebSocket.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/websockets/CBEventsWebSocket.java index 697011c5d4..b99ff76e93 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/websockets/CBEventsWebSocket.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/websockets/CBEventsWebSocket.java @@ -20,8 +20,8 @@ import io.cloudbeaver.model.session.BaseWebSession; import io.cloudbeaver.model.session.WebSession; import io.cloudbeaver.websocket.CBWebSessionEventHandler; +import org.eclipse.jetty.websocket.api.Callback; import org.eclipse.jetty.websocket.api.Session; -import org.eclipse.jetty.websocket.api.WriteCallback; import org.jkiss.code.NotNull; import org.jkiss.dbeaver.Log; import org.jkiss.dbeaver.model.websocket.event.WSClientEvent; @@ -36,7 +36,7 @@ public class CBEventsWebSocket extends CBAbstractWebSocket implements CBWebSessi @NotNull private final BaseWebSession webSession; @NotNull - private final WriteCallback callback; + private final Callback callback; public CBEventsWebSocket(@NotNull BaseWebSession webSession) { this.webSession = webSession; @@ -45,8 +45,8 @@ public CBEventsWebSocket(@NotNull BaseWebSession webSession) { } @Override - public void onWebSocketConnect(Session session) { - super.onWebSocketConnect(session); + public void onWebSocketOpen(Session session) { + super.onWebSocketOpen(session); this.webSession.addEventHandler(this); handleEvent(new WSSocketConnectedEvent(webSession.getApplication().getApplicationRunId())); log.debug("EventWebSocket connected to the " + webSession.getSessionId() + " session"); @@ -109,7 +109,7 @@ public void handleWebSessionEvent(WSEvent event) { super.handleEvent(event); } @Override - protected void handleEventException(Exception e) { + protected void handleEventException(Throwable e) { super.handleEventException(e); webSession.addSessionError(e); } @@ -120,7 +120,7 @@ public BaseWebSession getWebSession() { } @NotNull - public WriteCallback getCallback() { + public Callback getCallback() { return callback; } } diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/websockets/CBExpiredSessionWebSocket.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/websockets/CBExpiredSessionWebSocket.java index ec294713eb..643197d7e3 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/websockets/CBExpiredSessionWebSocket.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/websockets/CBExpiredSessionWebSocket.java @@ -21,8 +21,8 @@ public class CBExpiredSessionWebSocket extends CBAbstractWebSocket { @Override - public void onWebSocketConnect(Session session) { - super.onWebSocketConnect(session); + public void onWebSocketOpen(Session session) { + super.onWebSocketOpen(session); handleEvent(new WSAccessTokenExpiredEvent()); close(); } diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/websockets/CBJettyWebSocketManager.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/websockets/CBJettyWebSocketManager.java index 02c730dd10..26b958fbb2 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/websockets/CBJettyWebSocketManager.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/websockets/CBJettyWebSocketManager.java @@ -18,18 +18,19 @@ import io.cloudbeaver.model.session.BaseWebSession; import io.cloudbeaver.model.session.WebHeadlessSession; +import io.cloudbeaver.model.session.WebHttpRequestInfo; import io.cloudbeaver.server.CBPlatform; import io.cloudbeaver.service.session.WebSessionManager; -import jakarta.servlet.http.HttpServletRequest; -import org.eclipse.jetty.websocket.server.JettyServerUpgradeRequest; -import org.eclipse.jetty.websocket.server.JettyServerUpgradeResponse; -import org.eclipse.jetty.websocket.server.JettyWebSocketCreator; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.util.Callback; +import org.eclipse.jetty.websocket.server.ServerUpgradeRequest; +import org.eclipse.jetty.websocket.server.ServerUpgradeResponse; +import org.eclipse.jetty.websocket.server.WebSocketCreator; import org.jkiss.code.NotNull; import org.jkiss.code.Nullable; import org.jkiss.dbeaver.DBException; import org.jkiss.dbeaver.Log; import org.jkiss.dbeaver.model.security.exception.SMAccessTokenExpiredException; -import org.jkiss.dbeaver.runtime.DBWorkbench; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; @@ -38,7 +39,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; -public class CBJettyWebSocketManager implements JettyWebSocketCreator { +public class CBJettyWebSocketManager implements WebSocketCreator { private static final Log log = Log.getLog(CBJettyWebSocketManager.class); private final Map> socketBySessionId = new ConcurrentHashMap<>(); private final WebSessionManager webSessionManager; @@ -51,17 +52,22 @@ public CBJettyWebSocketManager(@NotNull WebSessionManager webSessionManager) { @Nullable @Override - public Object createWebSocket(@NotNull JettyServerUpgradeRequest request, JettyServerUpgradeResponse resp) { - var httpRequest = request.getHttpServletRequest(); - var webSession = webSessionManager.getOrRestoreSession(httpRequest); + public Object createWebSocket(@NotNull ServerUpgradeRequest request, ServerUpgradeResponse resp, Callback callback) { + var webSession = webSessionManager.getOrRestoreSession(request); + var requestInfo = new WebHttpRequestInfo( + request.getId(), + request.getAttribute("locale"), + Request.getRemoteAddr(request), + request.getHeaders().get("User-Agent") + ); if (webSession != null) { - webSession.updateSessionParameters(httpRequest); + webSession.updateSessionParameters(requestInfo); // web client session return createNewEventsWebSocket(webSession); } // possible desktop client session try { - var headlessSession = createHeadlessSession(httpRequest); + var headlessSession = createHeadlessSession(request); if (headlessSession == null) { log.debug("Couldn't create headless session"); return null; @@ -86,21 +92,21 @@ private CBEventsWebSocket createNewEventsWebSocket(@NotNull BaseWebSession webSe } @Nullable - private WebHeadlessSession createHeadlessSession(@NotNull HttpServletRequest request) throws DBException { - var httpSession = request.getSession(false); - if (httpSession == null) { + private WebHeadlessSession createHeadlessSession(@NotNull Request request) throws DBException { + var requestSession = request.getSession(false); + if (requestSession == null) { log.debug("CloudBeaver web session not exist, try to create headless session"); } else { - log.debug("CloudBeaver session not found with id " + httpSession.getId() + ", try to create headless session"); + log.debug("CloudBeaver session not found with id " + requestSession.getId() + ", try to create headless session"); } - return webSessionManager.getHeadlessSession(request, true); + return webSessionManager.getHeadlessSession(request, requestSession, true); } public void sendPing() { //remove expired sessions socketBySessionId.entrySet() .removeIf(entry -> { - entry.getValue().removeIf(ws -> !ws.isConnected()); + entry.getValue().removeIf(ws -> !ws.isOpen()); return webSessionManager.getSession(entry.getKey()) == null || entry.getValue().isEmpty(); } @@ -115,7 +121,7 @@ public void sendPing() { var webSockets = entry.getValue(); for (CBEventsWebSocket webSocket : webSockets) { try { - webSocket.getRemote().sendPing( + webSocket.getSession().sendPing( ByteBuffer.wrap("cb-ping".getBytes(StandardCharsets.UTF_8)), webSocket.getCallback() ); diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/websockets/WebSocketPingPongCallback.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/websockets/WebSocketPingPongCallback.java index 8530e963c1..b19741df9a 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/websockets/WebSocketPingPongCallback.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/websockets/WebSocketPingPongCallback.java @@ -1,6 +1,6 @@ /* * DBeaver - Universal Database Manager - * Copyright (C) 2010-2022 DBeaver Corp and others + * Copyright (C) 2010-2024 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,10 +18,10 @@ import io.cloudbeaver.model.session.BaseWebSession; import io.cloudbeaver.model.session.WebHeadlessSession; -import org.eclipse.jetty.websocket.api.WriteCallback; +import org.eclipse.jetty.websocket.api.Callback; import org.jkiss.code.NotNull; -public class WebSocketPingPongCallback implements WriteCallback { +public class WebSocketPingPongCallback implements Callback { @NotNull private final BaseWebSession webSession; @@ -30,7 +30,7 @@ public WebSocketPingPongCallback(@NotNull BaseWebSession webSession) { } @Override - public void writeSuccess() { + public void succeed() { if (webSession instanceof WebHeadlessSession) { webSession.touchSession(); } diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/session/WebSessionManager.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/session/WebSessionManager.java index 40dc20ae00..3380cd4872 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/session/WebSessionManager.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/session/WebSessionManager.java @@ -18,18 +18,18 @@ import io.cloudbeaver.DBWebException; import io.cloudbeaver.auth.SMTokenCredentialProvider; -import io.cloudbeaver.model.session.BaseWebSession; -import io.cloudbeaver.model.session.WebHeadlessSession; -import io.cloudbeaver.model.session.WebSession; -import io.cloudbeaver.model.session.WebSessionAuthProcessor; +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.events.WSWebUtils; import io.cloudbeaver.service.DBWSessionHandler; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpSession; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.Session; import org.jkiss.code.NotNull; import org.jkiss.code.Nullable; import org.jkiss.dbeaver.DBException; @@ -85,7 +85,8 @@ protected CBApplication getApplication() { public boolean touchSession(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response) throws DBWebException { WebSession webSession = getWebSession(request, response, false); - webSession.updateSessionParameters(request); + var requestInfo = new WebHttpRequestInfo(request); + webSession.updateSessionParameters(requestInfo); webSession.updateInfo(!request.getSession().isNew()); return true; } @@ -109,14 +110,14 @@ public WebSession getWebSession( var baseWebSession = sessionMap.get(sessionId); if (baseWebSession == null && CBApplication.getInstance().isConfigurationMode()) { try { - webSession = createWebSessionImpl(request); + webSession = createWebSessionImpl(new WebHttpRequestInfo(request)); } catch (DBException e) { throw new DBWebException("Failed to create web session", e); } sessionMap.put(sessionId, webSession); } else if (baseWebSession == null) { try { - webSession = createWebSessionImpl(request); + webSession = createWebSessionImpl(new WebHttpRequestInfo(request)); } catch (DBException e) { throw new DBWebException("Failed to create web session", e); } @@ -154,13 +155,15 @@ public WebSession getWebSession( * @return WebSession object or null, if session expired or invalid */ @Nullable - public WebSession getOrRestoreSession(@NotNull HttpServletRequest request) { - var httpSession = request.getSession(); - if (httpSession == null) { + public WebSession getOrRestoreSession(@NotNull Request request) { + var sessionIdCookie = Request.getCookies(request).stream().filter( + c -> c.getName().equals(CBConstants.CB_SESSION_COOKIE_NAME) + ).findAny().orElse(null); + if (sessionIdCookie == null) { log.debug("Http session is null. No Web Session returned"); return null; } - var sessionId = httpSession.getId(); + var sessionId = sessionIdCookie.getValue(); WebSession webSession; synchronized (sessionMap) { if (sessionMap.containsKey(sessionId)) { @@ -178,7 +181,12 @@ public WebSession getOrRestoreSession(@NotNull HttpServletRequest request) { return null; } - webSession = createWebSessionImpl(request); + webSession = createWebSessionImpl(new WebHttpRequestInfo( + request.getId(), + request.getAttribute("locale"), + Request.getRemoteAddr(request), + request.getHeaders().get("User-Agent") + )); restorePreviousUserSession(webSession, oldAuthInfo); sessionMap.put(sessionId, webSession); @@ -212,7 +220,7 @@ private void restorePreviousUserSession( } @NotNull - protected WebSession createWebSessionImpl(@NotNull HttpServletRequest request) throws DBException { + protected WebSession createWebSessionImpl(@NotNull WebHttpRequestInfo request) throws DBException { return new WebSession(request, application, getSessionHandlers()); } @@ -281,16 +289,15 @@ public Collection getAllActiveSessions() { } @Nullable - public WebHeadlessSession getHeadlessSession(HttpServletRequest request, boolean create) throws DBException { - String smAccessToken = request.getHeader(WSConstants.WS_AUTH_HEADER); + public WebHeadlessSession getHeadlessSession(Request request, Session session, boolean create) throws DBException { + String smAccessToken = request.getHeaders().get(WSConstants.WS_AUTH_HEADER); if (CommonUtils.isEmpty(smAccessToken)) { return null; } synchronized (sessionMap) { - var httpSession = request.getSession(); var tempCredProvider = new SMTokenCredentialProvider(smAccessToken); SMAuthPermissions authPermissions = application.createSecurityController(tempCredProvider).getTokenPermissions(); - var sessionId = httpSession != null ? httpSession.getId() + var sessionId = session != null ? session.getId() : authPermissions.getSessionId(); var existSession = sessionMap.get(sessionId); diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLFileLoaderServlet.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLFileLoaderServlet.java index 5ea8b52716..bc52ac542a 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLFileLoaderServlet.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLFileLoaderServlet.java @@ -29,7 +29,7 @@ import jakarta.servlet.annotation.MultipartConfig; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; -import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.ee10.servlet.ServletContextRequest; import org.jkiss.dbeaver.DBException; import org.jkiss.dbeaver.Log; import org.jkiss.dbeaver.model.data.json.JSONUtils; @@ -84,7 +84,7 @@ protected void processServiceRequest( .resolve(session.getSessionId()); MultipartConfigElement multiPartConfig = new MultipartConfigElement(tempFolder.toString()); - request.setAttribute(Request.__MULTIPART_CONFIG_ELEMENT, multiPartConfig); + request.setAttribute(ServletContextRequest.MULTIPART_CONFIG_ELEMENT, multiPartConfig); Map variables = gson.fromJson(request.getParameter(REQUEST_PARAM_VARIABLES), MAP_STRING_OBJECT_TYPE); diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLResultServlet.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLResultServlet.java index a0d231525e..31c5ff26f3 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLResultServlet.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLResultServlet.java @@ -1,3 +1,19 @@ +/* + * DBeaver - Universal Database Manager + * Copyright (C) 2010-2024 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.service.sql; import io.cloudbeaver.DBWebException; @@ -5,18 +21,18 @@ import io.cloudbeaver.server.CBApplication; import io.cloudbeaver.server.servlets.CBStaticServlet; import io.cloudbeaver.service.WebServiceServletBase; -import org.eclipse.jetty.server.Request; -import org.jkiss.dbeaver.DBException; -import org.jkiss.dbeaver.Log; -import org.jkiss.utils.CommonUtils; -import org.jkiss.utils.IOUtils; - import jakarta.servlet.MultipartConfigElement; import jakarta.servlet.ServletException; import jakarta.servlet.annotation.MultipartConfig; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.Part; +import org.eclipse.jetty.ee10.servlet.ServletContextRequest; +import org.jkiss.dbeaver.DBException; +import org.jkiss.dbeaver.Log; +import org.jkiss.utils.CommonUtils; +import org.jkiss.utils.IOUtils; + import java.io.IOException; import java.io.InputStream; import java.nio.file.Files; @@ -42,7 +58,7 @@ public WebSQLResultServlet(CBApplication application, DBWServiceSQL sqlService) @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { - request.setAttribute(Request.__MULTIPART_CONFIG_ELEMENT, MULTI_PART_CONFIG); + request.setAttribute(ServletContextRequest.MULTIPART_CONFIG_ELEMENT, MULTI_PART_CONFIG); String fileName = UUID.randomUUID().toString(); for (Part part : request.getParts()) { part.write(WebSQLDataLOBReceiver.DATA_EXPORT_FOLDER + "/" + fileName); diff --git a/server/bundles/io.cloudbeaver.service.fs/src/io/cloudbeaver/service/fs/model/WebFSServlet.java b/server/bundles/io.cloudbeaver.service.fs/src/io/cloudbeaver/service/fs/model/WebFSServlet.java index 53ac1a5dad..fa2514c98f 100644 --- a/server/bundles/io.cloudbeaver.service.fs/src/io/cloudbeaver/service/fs/model/WebFSServlet.java +++ b/server/bundles/io.cloudbeaver.service.fs/src/io/cloudbeaver/service/fs/model/WebFSServlet.java @@ -27,7 +27,7 @@ import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.Part; -import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.ee10.servlet.ServletContextRequest; import org.jkiss.dbeaver.DBException; import org.jkiss.dbeaver.model.data.json.JSONUtils; import org.jkiss.dbeaver.model.navigator.fs.DBNPathBase; @@ -79,7 +79,7 @@ private void doGet(WebSession session, HttpServletRequest request, HttpServletRe private void doPost(WebSession session, HttpServletRequest request, HttpServletResponse response) throws DBException, IOException { // we need to set this attribute to get parts - request.setAttribute(Request.__MULTIPART_CONFIG_ELEMENT, new MultipartConfigElement("")); + request.setAttribute(ServletContextRequest.MULTIPART_CONFIG_ELEMENT, new MultipartConfigElement("")); Map variables = getVariables(request); String parentNodePath = JSONUtils.getString(variables, "toParentNodePath"); if (CommonUtils.isEmpty(parentNodePath)) { From 2d1bde22a2ec463848fb208a627661a70cc1579f Mon Sep 17 00:00:00 2001 From: sergeyteleshev Date: Tue, 17 Sep 2024 19:14:34 +0200 Subject: [PATCH 6/7] Cb 5562 Fix bad this.setState for the new form API (#2903) * CB-5478 adds useAdministrationUserFormState with flexible id field * CB-5478 simplifies logic fork form state hooks * CB-5562 refactors form state and form parts * CB-5562 fixes disabled param for formState * CB-5562 comments cleanup * CB-5562 fixes getting of exceptions * CB-5562 baseform bad set state fix * CB-5562 removes load and configure method for forms * CB-5562 reverts some state.exception changes * CB-5562 removes bad set state from user form * CB-5562 cleanup * CB-5562 cleanup * CB-5562 removes bad set state from user form * CB-5562 fixes bad set state for user profile * CB-5562 pr fixes * CB-5562 pr fixes --------- Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com> --- .../core-ui/src/Form/Components/BaseForm.tsx | 9 +- webapp/packages/core-ui/src/Form/FormPart.ts | 22 +++- webapp/packages/core-ui/src/Form/FormState.ts | 115 +++++------------- webapp/packages/core-ui/src/Form/IFormPart.ts | 4 +- .../packages/core-ui/src/Form/IFormState.ts | 19 +-- .../Users/UserForm/AdministrationUserForm.tsx | 4 +- .../UserFormConnectionAccessPart.ts | 2 +- .../Users/UserForm/Info/UserFormInfoPart.ts | 17 +-- .../UserProfileFormAuthenticationPart.ts | 2 +- .../UserInfoPart/UserProfileFormInfoPart.ts | 2 +- .../UserProfileForm/UserProfileFormPanel.tsx | 2 +- 11 files changed, 68 insertions(+), 130 deletions(-) diff --git a/webapp/packages/core-ui/src/Form/Components/BaseForm.tsx b/webapp/packages/core-ui/src/Form/Components/BaseForm.tsx index e9de4a144b..96f18cc7c6 100644 --- a/webapp/packages/core-ui/src/Form/Components/BaseForm.tsx +++ b/webapp/packages/core-ui/src/Form/Components/BaseForm.tsx @@ -7,7 +7,7 @@ */ import { observer } from 'mobx-react-lite'; -import { Button, Container, Form, s, StatusMessage, useAutoLoad, useForm, useS, useTranslate } from '@cloudbeaver/core-blocks'; +import { Button, Container, Form, getComputed, s, StatusMessage, useForm, useS, useTranslate } from '@cloudbeaver/core-blocks'; import { getFirstException } from '@cloudbeaver/core-utils'; import { TabList } from '../../Tabs/TabList'; @@ -22,7 +22,8 @@ export const BaseForm = observer>(function BaseForm({ servic const translate = useTranslate(); const editing = state.mode === FormMode.Edit; - const changed = state.isChanged(); + const changed = state.isChanged; + const error = getComputed(() => getFirstException(state.exception)); const form = useForm({ async onSubmit() { @@ -36,15 +37,13 @@ export const BaseForm = observer>(function BaseForm({ servic }, }); - useAutoLoad(BaseForm, state); - return (
- + diff --git a/webapp/packages/core-ui/src/Form/FormPart.ts b/webapp/packages/core-ui/src/Form/FormPart.ts index 2dcf2063d7..c789e0df64 100644 --- a/webapp/packages/core-ui/src/Form/FormPart.ts +++ b/webapp/packages/core-ui/src/Form/FormPart.ts @@ -5,7 +5,7 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ -import { action, makeObservable, observable, toJS } from 'mobx'; +import { action, computed, makeObservable, observable, toJS } from 'mobx'; import { executorHandlerFilter, ExecutorInterrupter, type IExecutionContextProvider } from '@cloudbeaver/core-executor'; import { isObjectsEqual } from '@cloudbeaver/core-utils'; @@ -16,6 +16,7 @@ import type { IFormState } from './IFormState'; export abstract class FormPart implements IFormPart { state: TPartState; initialState: TPartState; + isSaving: boolean; exception: Error | null; promise: Promise | null; @@ -29,6 +30,7 @@ export abstract class FormPart implements IFormPar ) { this.initialState = initialState; this.state = toJS(this.initialState); + this.isSaving = false; this.exception = null; this.promise = null; @@ -37,7 +39,6 @@ export abstract class FormPart implements IFormPar this.loading = false; this.formState.submitTask.addHandler(executorHandlerFilter(() => this.isLoaded(), this.save.bind(this))); - this.formState.configureTask.addHandler(executorHandlerFilter(() => this.isLoaded(), this.configure.bind(this))); this.formState.formatTask.addHandler(executorHandlerFilter(() => this.isLoaded(), this.format.bind(this))); this.formState.validationTask.addHandler(executorHandlerFilter(() => this.isLoaded(), this.validate.bind(this))); @@ -46,12 +47,19 @@ export abstract class FormPart implements IFormPar state: observable, exception: observable.ref, promise: observable.ref, + isSaving: observable.ref, loaded: observable, loading: observable, setInitialState: action, + isDisabled: computed, + isChanged: computed, }); } + get isDisabled(): boolean { + return this.isSaving || this.isLoading(); + } + isLoading(): boolean { return this.loading; } @@ -68,7 +76,7 @@ export abstract class FormPart implements IFormPar return this.exception !== null; } - isChanged(): boolean { + get isChanged(): boolean { if (!this.loaded || this.initialState === this.state) { return false; } @@ -85,10 +93,12 @@ export abstract class FormPart implements IFormPar try { await this.loader(); - if (!this.isChanged()) { + if (!this.isChanged) { return; } + this.isSaving = true; + await this.saveChanges(data, contexts); if (ExecutorInterrupter.isInterrupted(contexts)) { return; @@ -100,6 +110,7 @@ export abstract class FormPart implements IFormPar this.exception = exception; throw exception; } finally { + this.isSaving = false; this.loading = false; } } @@ -136,7 +147,7 @@ export abstract class FormPart implements IFormPar protected setInitialState(initialState: TPartState) { this.initialState = initialState; - if (this.isChanged()) { + if (this.isChanged) { return; } @@ -147,7 +158,6 @@ export abstract class FormPart implements IFormPar this.state = state; } - protected configure(data: IFormState, contexts: IExecutionContextProvider>): void | Promise {} protected format(data: IFormState, contexts: IExecutionContextProvider>): void | Promise {} protected validate(data: IFormState, contexts: IExecutionContextProvider>): void | Promise {} diff --git a/webapp/packages/core-ui/src/Form/FormState.ts b/webapp/packages/core-ui/src/Form/FormState.ts index 2b651eda81..93bd21daa2 100644 --- a/webapp/packages/core-ui/src/Form/FormState.ts +++ b/webapp/packages/core-ui/src/Form/FormState.ts @@ -11,7 +11,7 @@ import { DataContext, dataContextAddDIProvider, DataContextGetter, type IDataCon import type { IServiceProvider } from '@cloudbeaver/core-di'; import type { ENotificationType } from '@cloudbeaver/core-events'; import { Executor, ExecutorInterrupter, IExecutionContextProvider, type IExecutor } from '@cloudbeaver/core-executor'; -import { isLoadableStateHasException, MetadataMap, uuid } from '@cloudbeaver/core-utils'; +import { isArraysEqual, isNotNullDefined, MetadataMap, uuid } from '@cloudbeaver/core-utils'; import { DATA_CONTEXT_LOADABLE_STATE, loadableStateContext } from '@cloudbeaver/core-view'; import { DATA_CONTEXT_FORM_STATE } from './DATA_CONTEXT_FORM_STATE'; @@ -25,23 +25,24 @@ export class FormState implements IFormState { mode: FormMode; parts: MetadataMap>; state: TState; - isSaving: boolean; statusMessage: string | string[] | null; statusType: ENotificationType | null; - exception: Error | (Error | null)[] | null; promise: Promise | null; get isDisabled(): boolean { - return this.isSaving || this.isLoading(); + return this.partsValues.some(part => part.isSaving || part?.isLoading?.()); + } + + get isSaving(): boolean { + return this.partsValues.some(part => part.isSaving); } readonly id: string; readonly service: FormBaseService; readonly dataContext: IDataContext; - readonly configureTask: IExecutor>; readonly formStateTask: IExecutor; readonly fillDefaultConfigTask: IExecutor>; readonly submitTask: IExecutor>; @@ -56,17 +57,12 @@ export class FormState implements IFormState { this.mode = FormMode.Create; this.parts = new MetadataMap(); this.state = state; - this.isSaving = false; this.statusMessage = null; this.statusType = null; - this.exception = null; this.promise = null; - this.configureTask = new Executor(this as IFormState, () => true); - this.configureTask.addCollection(service.onConfigure); - this.formStateTask = new Executor(state, () => true); this.formStateTask.addCollection(service.onState).addPostHandler(this.updateFormState.bind(this)); @@ -90,42 +86,43 @@ export class FormState implements IFormState { mode: observable, parts: observable.ref, promise: observable.ref, - exception: observable.ref, - isSaving: observable.ref, state: observable, + isSaving: computed, + exception: computed, isDisabled: computed, setMode: action, setPartsState: action, - setException: action, setState: action, + isChanged: computed, + partsValues: computed[]>({ + equals: isArraysEqual, + }), + isError: computed, + isCancelled: computed, }); } - isLoading(): boolean { - return this.promise !== null || this.dataContext.get(DATA_CONTEXT_LOADABLE_STATE)!.loaders.some(loader => loader.isLoading()); - } - - isLoaded(): boolean { - if (this.promise) { - return false; - } - return this.dataContext.get(DATA_CONTEXT_LOADABLE_STATE)!.loaders.every(loader => loader.isLoaded()); + get partsValues() { + return Array.from(this.parts.values()); } - isError(): boolean { - return this.dataContext.get(DATA_CONTEXT_LOADABLE_STATE)!.loaders.some(loader => loader.isError()); + get exception(): Error | (Error | null)[] | null { + return this.partsValues + .map(part => part?.exception) + .flat() + .filter(isNotNullDefined); } - isOutdated(): boolean { - return this.dataContext.get(DATA_CONTEXT_LOADABLE_STATE)!.loaders.some(loader => loader.isOutdated?.() === true); + get isError(): boolean { + return this.partsValues.some(part => part.isError()); } - isCancelled(): boolean { - return this.dataContext.get(DATA_CONTEXT_LOADABLE_STATE)!.loaders.some(loader => loader.isCancelled?.() === true); + get isCancelled(): boolean { + return this.partsValues.some(part => part?.isCancelled?.()); } - isChanged(): boolean { - return Array.from(this.parts.values()).some(part => part.isChanged()); + get isChanged(): boolean { + return this.partsValues.some(part => part.isChanged); } getPart>(getter: DataContextGetter, init: (context: IDataContext, id: string) => T): T { @@ -140,50 +137,6 @@ export class FormState implements IFormState { }) as T; } - async load(refresh?: boolean): Promise { - if (this.promise !== null) { - return this.promise; - } - - if (this.isLoaded() && !this.isOutdated() && !refresh) { - return; - } - - this.promise = (async () => { - try { - await this.configureTask.execute(this); - - const loaders = this.dataContext.get(DATA_CONTEXT_LOADABLE_STATE)!.loaders; - - for (const loader of loaders) { - if (isLoadableStateHasException(loader)) { - continue; - } - - if (!loader.isLoaded() || loader.isOutdated?.() === true) { - try { - await loader.load(); - } catch { - return; - } - } - } - - await this.fillDefaultConfigTask.execute(this); - this.exception = null; - } catch (exception: any) { - this.exception = exception; - throw exception; - } finally { - this.promise = null; - } - })(); - } - - async reload(): Promise { - await this.load(true); - } - cancel(): void { const loaders = this.dataContext.get(DATA_CONTEXT_LOADABLE_STATE)!.loaders; @@ -210,11 +163,6 @@ export class FormState implements IFormState { return this; } - setException(exception: Error | (Error | null)[] | null): this { - this.exception = exception; - return this; - } - setState(state: TState): this { this.state = state; return this; @@ -222,20 +170,15 @@ export class FormState implements IFormState { async save(): Promise { try { - this.isSaving = true; const context = await this.submitTask.execute(this); if (ExecutorInterrupter.isInterrupted(context)) { return false; } - this.exception = null; return true; - } catch (exception: any) { - this.exception = exception; - } finally { - this.isSaving = false; - } + } catch (exception: any) {} + return false; } diff --git a/webapp/packages/core-ui/src/Form/IFormPart.ts b/webapp/packages/core-ui/src/Form/IFormPart.ts index faa9e63117..446c33fd97 100644 --- a/webapp/packages/core-ui/src/Form/IFormPart.ts +++ b/webapp/packages/core-ui/src/Form/IFormPart.ts @@ -10,8 +10,10 @@ import type { ILoadableState } from '@cloudbeaver/core-utils'; export interface IFormPart extends ILoadableState { readonly state: TState; readonly initialState: TState; + isSaving: boolean; + readonly isDisabled: boolean; - isChanged(): boolean; + readonly isChanged: boolean; load(): Promise; reset(): void; diff --git a/webapp/packages/core-ui/src/Form/IFormState.ts b/webapp/packages/core-ui/src/Form/IFormState.ts index 67b2029e1f..050332649b 100644 --- a/webapp/packages/core-ui/src/Form/IFormState.ts +++ b/webapp/packages/core-ui/src/Form/IFormState.ts @@ -8,13 +8,13 @@ import type { DataContextGetter, IDataContext } from '@cloudbeaver/core-data-context'; import type { ENotificationType } from '@cloudbeaver/core-events'; import type { IExecutor } from '@cloudbeaver/core-executor'; -import type { ILoadableState, MetadataMap } from '@cloudbeaver/core-utils'; +import type { MetadataMap } from '@cloudbeaver/core-utils'; import type { FormBaseService } from './FormBaseService'; import type { FormMode } from './FormMode'; import type { IFormPart } from './IFormPart'; -export interface IFormState extends ILoadableState { +export interface IFormState { readonly id: string; readonly service: FormBaseService; readonly dataContext: IDataContext; @@ -23,14 +23,13 @@ export interface IFormState extends ILoadableState { readonly parts: MetadataMap; readonly state: TState; readonly isDisabled: boolean; + readonly exception: Error | (Error | null)[] | null; readonly promise: Promise | null; - readonly exception: Error | (Error | null)[] | null; readonly statusMessage: string | string[] | null; readonly statusType: ENotificationType | null; - readonly configureTask: IExecutor>; readonly formStateTask: IExecutor; readonly fillDefaultConfigTask: IExecutor>; readonly submitTask: IExecutor>; @@ -39,20 +38,14 @@ export interface IFormState extends ILoadableState { setMode(mode: FormMode): this; setPartsState(state: MetadataMap): this; - setException(exception: Error | (Error | null)[] | null): this; setState(state: TState): this; getPart>(getter: DataContextGetter, init: (context: IDataContext, id: string) => T): T; - isLoading(): boolean; - isLoaded(): boolean; - isError(): boolean; - isOutdated(): boolean; - isCancelled(): boolean; - isChanged(): boolean; + isError: boolean; + isCancelled: boolean; + isChanged: boolean; - load(): Promise; - reload(): Promise; save(): Promise; reset(): void; cancel(): void; diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/AdministrationUserForm.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/AdministrationUserForm.tsx index 5c006048a7..99bd4c784e 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/AdministrationUserForm.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/AdministrationUserForm.tsx @@ -59,7 +59,7 @@ export const AdministrationUserForm = observer(function AdministrationUse }, }); - useAutoLoad(AdministrationUserForm, state); + useAutoLoad(AdministrationUserForm, [userFormInfoPart]); return ( @@ -69,7 +69,7 @@ export const AdministrationUserForm = observer(function AdministrationUse diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/ConnectionAccess/UserFormConnectionAccessPart.ts b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/ConnectionAccess/UserFormConnectionAccessPart.ts index 5e7d6ea83b..6cc4e3cf2a 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/ConnectionAccess/UserFormConnectionAccessPart.ts +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/ConnectionAccess/UserFormConnectionAccessPart.ts @@ -24,7 +24,7 @@ export class UserFormConnectionAccessPart extends FormPart [ - getCachedDataResourceLoaderState(this.serverConfigResource, () => undefined), - getCachedDataResourceLoaderState(this.authRolesResource, () => undefined), - ]); - } private async updateCredentials() { const password = this.state.password; @@ -220,7 +211,7 @@ export class UserFormInfoPart extends FormPart Date: Tue, 17 Sep 2024 20:46:54 +0200 Subject: [PATCH 7/7] 24.2.1 version bump --- server/bundles/io.cloudbeaver.model/META-INF/MANIFEST.MF | 4 ++-- server/bundles/io.cloudbeaver.model/pom.xml | 2 +- server/bundles/io.cloudbeaver.product.ce/META-INF/MANIFEST.MF | 4 ++-- server/bundles/io.cloudbeaver.product.ce/pom.xml | 2 +- .../META-INF/MANIFEST.MF | 4 ++-- server/bundles/io.cloudbeaver.resources.drivers.base/pom.xml | 2 +- server/bundles/io.cloudbeaver.server/META-INF/MANIFEST.MF | 4 ++-- server/bundles/io.cloudbeaver.server/pom.xml | 2 +- .../bundles/io.cloudbeaver.service.admin/META-INF/MANIFEST.MF | 4 ++-- server/bundles/io.cloudbeaver.service.admin/pom.xml | 2 +- .../bundles/io.cloudbeaver.service.auth/META-INF/MANIFEST.MF | 4 ++-- server/bundles/io.cloudbeaver.service.auth/pom.xml | 2 +- .../io.cloudbeaver.service.data.transfer/META-INF/MANIFEST.MF | 4 ++-- server/bundles/io.cloudbeaver.service.data.transfer/pom.xml | 2 +- server/bundles/io.cloudbeaver.service.fs/META-INF/MANIFEST.MF | 4 ++-- server/bundles/io.cloudbeaver.service.fs/pom.xml | 2 +- .../io.cloudbeaver.service.metadata/META-INF/MANIFEST.MF | 4 ++-- server/bundles/io.cloudbeaver.service.metadata/pom.xml | 2 +- .../io.cloudbeaver.service.rm.nio/META-INF/MANIFEST.MF | 4 ++-- server/bundles/io.cloudbeaver.service.rm.nio/pom.xml | 2 +- server/bundles/io.cloudbeaver.service.rm/META-INF/MANIFEST.MF | 4 ++-- server/bundles/io.cloudbeaver.service.rm/pom.xml | 2 +- .../io.cloudbeaver.service.security/META-INF/MANIFEST.MF | 4 ++-- server/bundles/io.cloudbeaver.service.security/pom.xml | 2 +- server/bundles/io.cloudbeaver.slf4j/META-INF/MANIFEST.MF | 4 ++-- server/bundles/io.cloudbeaver.slf4j/pom.xml | 2 +- server/features/io.cloudbeaver.ce.drivers.feature/feature.xml | 2 +- server/features/io.cloudbeaver.ce.drivers.feature/pom.xml | 2 +- server/features/io.cloudbeaver.product.ce.feature/feature.xml | 2 +- server/features/io.cloudbeaver.product.ce.feature/pom.xml | 2 +- server/features/io.cloudbeaver.server.feature/feature.xml | 2 +- server/features/io.cloudbeaver.server.feature/pom.xml | 2 +- server/features/io.cloudbeaver.ws.feature/feature.xml | 2 +- server/features/io.cloudbeaver.ws.feature/pom.xml | 2 +- server/pom.xml | 2 +- server/product/web-server/CloudbeaverServer.product | 2 +- server/product/web-server/pom.xml | 2 +- 37 files changed, 50 insertions(+), 50 deletions(-) diff --git a/server/bundles/io.cloudbeaver.model/META-INF/MANIFEST.MF b/server/bundles/io.cloudbeaver.model/META-INF/MANIFEST.MF index b1a8d173c5..226b75a8b0 100644 --- a/server/bundles/io.cloudbeaver.model/META-INF/MANIFEST.MF +++ b/server/bundles/io.cloudbeaver.model/META-INF/MANIFEST.MF @@ -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.61.qualifier -Bundle-Release-Date: 20240923 +Bundle-Version: 1.0.62.qualifier +Bundle-Release-Date: 20241007 Bundle-RequiredExecutionEnvironment: JavaSE-17 Bundle-ActivationPolicy: lazy Bundle-ClassPath: . diff --git a/server/bundles/io.cloudbeaver.model/pom.xml b/server/bundles/io.cloudbeaver.model/pom.xml index feddc91ae6..421eb0e899 100644 --- a/server/bundles/io.cloudbeaver.model/pom.xml +++ b/server/bundles/io.cloudbeaver.model/pom.xml @@ -10,7 +10,7 @@ ../ io.cloudbeaver.model - 1.0.61-SNAPSHOT + 1.0.62-SNAPSHOT eclipse-plugin diff --git a/server/bundles/io.cloudbeaver.product.ce/META-INF/MANIFEST.MF b/server/bundles/io.cloudbeaver.product.ce/META-INF/MANIFEST.MF index e352f3816b..f10b82c773 100644 --- a/server/bundles/io.cloudbeaver.product.ce/META-INF/MANIFEST.MF +++ b/server/bundles/io.cloudbeaver.product.ce/META-INF/MANIFEST.MF @@ -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: 24.2.1.qualifier -Bundle-Release-Date: 20240923 +Bundle-Version: 24.2.2.qualifier +Bundle-Release-Date: 20241007 Bundle-RequiredExecutionEnvironment: JavaSE-17 Bundle-ActivationPolicy: lazy Bundle-ClassPath: . diff --git a/server/bundles/io.cloudbeaver.product.ce/pom.xml b/server/bundles/io.cloudbeaver.product.ce/pom.xml index daafc53e12..74fb225380 100644 --- a/server/bundles/io.cloudbeaver.product.ce/pom.xml +++ b/server/bundles/io.cloudbeaver.product.ce/pom.xml @@ -10,7 +10,7 @@ ../ io.cloudbeaver.product.ce - 24.2.1-SNAPSHOT + 24.2.2-SNAPSHOT eclipse-plugin diff --git a/server/bundles/io.cloudbeaver.resources.drivers.base/META-INF/MANIFEST.MF b/server/bundles/io.cloudbeaver.resources.drivers.base/META-INF/MANIFEST.MF index 8cbfa5fc84..1a26e7e53e 100644 --- a/server/bundles/io.cloudbeaver.resources.drivers.base/META-INF/MANIFEST.MF +++ b/server/bundles/io.cloudbeaver.resources.drivers.base/META-INF/MANIFEST.MF @@ -2,8 +2,8 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Base JDBC drivers Bundle-SymbolicName: io.cloudbeaver.resources.drivers.base;singleton:=true -Bundle-Version: 1.0.106.qualifier -Bundle-Release-Date: 20240923 +Bundle-Version: 1.0.107.qualifier +Bundle-Release-Date: 20241007 Bundle-Vendor: DBeaver Corp Bundle-ActivationPolicy: lazy Automatic-Module-Name: io.cloudbeaver.resources.drivers.base diff --git a/server/bundles/io.cloudbeaver.resources.drivers.base/pom.xml b/server/bundles/io.cloudbeaver.resources.drivers.base/pom.xml index 6325eb04b9..8831414e5b 100644 --- a/server/bundles/io.cloudbeaver.resources.drivers.base/pom.xml +++ b/server/bundles/io.cloudbeaver.resources.drivers.base/pom.xml @@ -9,6 +9,6 @@ ../ io.cloudbeaver.resources.drivers.base - 1.0.106-SNAPSHOT + 1.0.107-SNAPSHOT eclipse-plugin diff --git a/server/bundles/io.cloudbeaver.server/META-INF/MANIFEST.MF b/server/bundles/io.cloudbeaver.server/META-INF/MANIFEST.MF index 15de9b77ce..93455b8266 100644 --- a/server/bundles/io.cloudbeaver.server/META-INF/MANIFEST.MF +++ b/server/bundles/io.cloudbeaver.server/META-INF/MANIFEST.MF @@ -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: 24.2.1.qualifier -Bundle-Release-Date: 20240923 +Bundle-Version: 24.2.2.qualifier +Bundle-Release-Date: 20241007 Bundle-RequiredExecutionEnvironment: JavaSE-17 Bundle-ActivationPolicy: lazy Bundle-Activator: io.cloudbeaver.server.CBPlatformActivator diff --git a/server/bundles/io.cloudbeaver.server/pom.xml b/server/bundles/io.cloudbeaver.server/pom.xml index cf53c858bd..1b33a40193 100644 --- a/server/bundles/io.cloudbeaver.server/pom.xml +++ b/server/bundles/io.cloudbeaver.server/pom.xml @@ -10,7 +10,7 @@ ../ io.cloudbeaver.server - 24.2.1-SNAPSHOT + 24.2.2-SNAPSHOT eclipse-plugin diff --git a/server/bundles/io.cloudbeaver.service.admin/META-INF/MANIFEST.MF b/server/bundles/io.cloudbeaver.service.admin/META-INF/MANIFEST.MF index 9602219ee4..6b10865c0b 100644 --- a/server/bundles/io.cloudbeaver.service.admin/META-INF/MANIFEST.MF +++ b/server/bundles/io.cloudbeaver.service.admin/META-INF/MANIFEST.MF @@ -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.105.qualifier -Bundle-Release-Date: 20240923 +Bundle-Version: 1.0.106.qualifier +Bundle-Release-Date: 20241007 Bundle-RequiredExecutionEnvironment: JavaSE-17 Bundle-ActivationPolicy: lazy Bundle-ClassPath: . diff --git a/server/bundles/io.cloudbeaver.service.admin/pom.xml b/server/bundles/io.cloudbeaver.service.admin/pom.xml index f200105f1a..cc6d869b22 100644 --- a/server/bundles/io.cloudbeaver.service.admin/pom.xml +++ b/server/bundles/io.cloudbeaver.service.admin/pom.xml @@ -10,7 +10,7 @@ ../ io.cloudbeaver.service.admin - 1.0.105-SNAPSHOT + 1.0.106-SNAPSHOT eclipse-plugin diff --git a/server/bundles/io.cloudbeaver.service.auth/META-INF/MANIFEST.MF b/server/bundles/io.cloudbeaver.service.auth/META-INF/MANIFEST.MF index 3481f6c816..fbc470b0f7 100644 --- a/server/bundles/io.cloudbeaver.service.auth/META-INF/MANIFEST.MF +++ b/server/bundles/io.cloudbeaver.service.auth/META-INF/MANIFEST.MF @@ -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.105.qualifier -Bundle-Release-Date: 20240923 +Bundle-Version: 1.0.106.qualifier +Bundle-Release-Date: 20241007 Bundle-RequiredExecutionEnvironment: JavaSE-17 Bundle-ActivationPolicy: lazy Bundle-ClassPath: . diff --git a/server/bundles/io.cloudbeaver.service.auth/pom.xml b/server/bundles/io.cloudbeaver.service.auth/pom.xml index b3c214f1f2..7bff8ea860 100644 --- a/server/bundles/io.cloudbeaver.service.auth/pom.xml +++ b/server/bundles/io.cloudbeaver.service.auth/pom.xml @@ -10,7 +10,7 @@ ../ io.cloudbeaver.service.auth - 1.0.105-SNAPSHOT + 1.0.106-SNAPSHOT eclipse-plugin diff --git a/server/bundles/io.cloudbeaver.service.data.transfer/META-INF/MANIFEST.MF b/server/bundles/io.cloudbeaver.service.data.transfer/META-INF/MANIFEST.MF index bcddeb66ac..f5250bd4cc 100644 --- a/server/bundles/io.cloudbeaver.service.data.transfer/META-INF/MANIFEST.MF +++ b/server/bundles/io.cloudbeaver.service.data.transfer/META-INF/MANIFEST.MF @@ -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.106.qualifier -Bundle-Release-Date: 20240923 +Bundle-Version: 1.0.107.qualifier +Bundle-Release-Date: 20241007 Bundle-RequiredExecutionEnvironment: JavaSE-17 Bundle-ActivationPolicy: lazy Bundle-ClassPath: . diff --git a/server/bundles/io.cloudbeaver.service.data.transfer/pom.xml b/server/bundles/io.cloudbeaver.service.data.transfer/pom.xml index aa3b788ab9..185a1d5222 100644 --- a/server/bundles/io.cloudbeaver.service.data.transfer/pom.xml +++ b/server/bundles/io.cloudbeaver.service.data.transfer/pom.xml @@ -10,7 +10,7 @@ ../ io.cloudbeaver.service.data.transfer - 1.0.106-SNAPSHOT + 1.0.107-SNAPSHOT eclipse-plugin diff --git a/server/bundles/io.cloudbeaver.service.fs/META-INF/MANIFEST.MF b/server/bundles/io.cloudbeaver.service.fs/META-INF/MANIFEST.MF index 25acfd3be3..f87beec385 100644 --- a/server/bundles/io.cloudbeaver.service.fs/META-INF/MANIFEST.MF +++ b/server/bundles/io.cloudbeaver.service.fs/META-INF/MANIFEST.MF @@ -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.23.qualifier -Bundle-Release-Date: 20240923 +Bundle-Version: 1.0.24.qualifier +Bundle-Release-Date: 20241007 Bundle-RequiredExecutionEnvironment: JavaSE-17 Bundle-ActivationPolicy: lazy Bundle-ClassPath: . diff --git a/server/bundles/io.cloudbeaver.service.fs/pom.xml b/server/bundles/io.cloudbeaver.service.fs/pom.xml index 8f6b7cae02..52d9291e87 100644 --- a/server/bundles/io.cloudbeaver.service.fs/pom.xml +++ b/server/bundles/io.cloudbeaver.service.fs/pom.xml @@ -10,7 +10,7 @@ ../ io.cloudbeaver.service.fs - 1.0.23-SNAPSHOT + 1.0.24-SNAPSHOT eclipse-plugin diff --git a/server/bundles/io.cloudbeaver.service.metadata/META-INF/MANIFEST.MF b/server/bundles/io.cloudbeaver.service.metadata/META-INF/MANIFEST.MF index 26f8bbe9d5..8f2fa9480d 100644 --- a/server/bundles/io.cloudbeaver.service.metadata/META-INF/MANIFEST.MF +++ b/server/bundles/io.cloudbeaver.service.metadata/META-INF/MANIFEST.MF @@ -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.109.qualifier -Bundle-Release-Date: 20240923 +Bundle-Version: 1.0.110.qualifier +Bundle-Release-Date: 20241007 Bundle-RequiredExecutionEnvironment: JavaSE-17 Bundle-ActivationPolicy: lazy Bundle-ClassPath: . diff --git a/server/bundles/io.cloudbeaver.service.metadata/pom.xml b/server/bundles/io.cloudbeaver.service.metadata/pom.xml index 52997551fa..f97daaaaaa 100644 --- a/server/bundles/io.cloudbeaver.service.metadata/pom.xml +++ b/server/bundles/io.cloudbeaver.service.metadata/pom.xml @@ -10,7 +10,7 @@ ../ io.cloudbeaver.service.metadata - 1.0.109-SNAPSHOT + 1.0.110-SNAPSHOT eclipse-plugin diff --git a/server/bundles/io.cloudbeaver.service.rm.nio/META-INF/MANIFEST.MF b/server/bundles/io.cloudbeaver.service.rm.nio/META-INF/MANIFEST.MF index 737a39ad87..c2fbcd9eac 100644 --- a/server/bundles/io.cloudbeaver.service.rm.nio/META-INF/MANIFEST.MF +++ b/server/bundles/io.cloudbeaver.service.rm.nio/META-INF/MANIFEST.MF @@ -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.23.qualifier -Bundle-Release-Date: 20240923 +Bundle-Version: 1.0.24.qualifier +Bundle-Release-Date: 20241007 Bundle-RequiredExecutionEnvironment: JavaSE-17 Bundle-ActivationPolicy: lazy Bundle-ClassPath: . diff --git a/server/bundles/io.cloudbeaver.service.rm.nio/pom.xml b/server/bundles/io.cloudbeaver.service.rm.nio/pom.xml index aae7ab9f48..73a645ff48 100644 --- a/server/bundles/io.cloudbeaver.service.rm.nio/pom.xml +++ b/server/bundles/io.cloudbeaver.service.rm.nio/pom.xml @@ -10,7 +10,7 @@ ../ io.cloudbeaver.service.rm.nio - 1.0.23-SNAPSHOT + 1.0.24-SNAPSHOT eclipse-plugin diff --git a/server/bundles/io.cloudbeaver.service.rm/META-INF/MANIFEST.MF b/server/bundles/io.cloudbeaver.service.rm/META-INF/MANIFEST.MF index c9829ed966..31ae2dab47 100644 --- a/server/bundles/io.cloudbeaver.service.rm/META-INF/MANIFEST.MF +++ b/server/bundles/io.cloudbeaver.service.rm/META-INF/MANIFEST.MF @@ -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.58.qualifier -Bundle-Release-Date: 20240923 +Bundle-Version: 1.0.59.qualifier +Bundle-Release-Date: 20241007 Bundle-RequiredExecutionEnvironment: JavaSE-17 Bundle-ActivationPolicy: lazy Bundle-ClassPath: . diff --git a/server/bundles/io.cloudbeaver.service.rm/pom.xml b/server/bundles/io.cloudbeaver.service.rm/pom.xml index 8951e0b0f0..a46196fd8e 100644 --- a/server/bundles/io.cloudbeaver.service.rm/pom.xml +++ b/server/bundles/io.cloudbeaver.service.rm/pom.xml @@ -10,7 +10,7 @@ ../ io.cloudbeaver.service.rm - 1.0.58-SNAPSHOT + 1.0.59-SNAPSHOT eclipse-plugin diff --git a/server/bundles/io.cloudbeaver.service.security/META-INF/MANIFEST.MF b/server/bundles/io.cloudbeaver.service.security/META-INF/MANIFEST.MF index 8a8a30cb1a..514653ed5f 100644 --- a/server/bundles/io.cloudbeaver.service.security/META-INF/MANIFEST.MF +++ b/server/bundles/io.cloudbeaver.service.security/META-INF/MANIFEST.MF @@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2 Bundle-Vendor: Cloudbeaver Web Service - Security Bundle-Vendor: DBeaver Corp Bundle-SymbolicName: io.cloudbeaver.service.security;singleton:=true -Bundle-Version: 1.0.61.qualifier -Bundle-Release-Date: 20240923 +Bundle-Version: 1.0.62.qualifier +Bundle-Release-Date: 20241007 Bundle-RequiredExecutionEnvironment: JavaSE-17 Bundle-ActivationPolicy: lazy Bundle-ClassPath: . diff --git a/server/bundles/io.cloudbeaver.service.security/pom.xml b/server/bundles/io.cloudbeaver.service.security/pom.xml index beea19d866..939a65afd6 100644 --- a/server/bundles/io.cloudbeaver.service.security/pom.xml +++ b/server/bundles/io.cloudbeaver.service.security/pom.xml @@ -10,7 +10,7 @@ ../ io.cloudbeaver.service.security - 1.0.61-SNAPSHOT + 1.0.62-SNAPSHOT eclipse-plugin diff --git a/server/bundles/io.cloudbeaver.slf4j/META-INF/MANIFEST.MF b/server/bundles/io.cloudbeaver.slf4j/META-INF/MANIFEST.MF index cfe182e73f..ed1d71160f 100644 --- a/server/bundles/io.cloudbeaver.slf4j/META-INF/MANIFEST.MF +++ b/server/bundles/io.cloudbeaver.slf4j/META-INF/MANIFEST.MF @@ -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.21.qualifier -Bundle-Release-Date: 20240923 +Bundle-Version: 1.0.22.qualifier +Bundle-Release-Date: 20241007 Bundle-RequiredExecutionEnvironment: JavaSE-17 Bundle-ActivationPolicy: lazy Bundle-ClassPath: . diff --git a/server/bundles/io.cloudbeaver.slf4j/pom.xml b/server/bundles/io.cloudbeaver.slf4j/pom.xml index ecf17e15b3..cbcfbb5d15 100644 --- a/server/bundles/io.cloudbeaver.slf4j/pom.xml +++ b/server/bundles/io.cloudbeaver.slf4j/pom.xml @@ -10,7 +10,7 @@ ../ io.cloudbeaver.slf4j - 1.0.21-SNAPSHOT + 1.0.22-SNAPSHOT eclipse-plugin diff --git a/server/features/io.cloudbeaver.ce.drivers.feature/feature.xml b/server/features/io.cloudbeaver.ce.drivers.feature/feature.xml index f92eae44dc..77b67fe77c 100644 --- a/server/features/io.cloudbeaver.ce.drivers.feature/feature.xml +++ b/server/features/io.cloudbeaver.ce.drivers.feature/feature.xml @@ -2,7 +2,7 @@ diff --git a/server/features/io.cloudbeaver.ce.drivers.feature/pom.xml b/server/features/io.cloudbeaver.ce.drivers.feature/pom.xml index 38579f0ce9..b2d7dbda84 100644 --- a/server/features/io.cloudbeaver.ce.drivers.feature/pom.xml +++ b/server/features/io.cloudbeaver.ce.drivers.feature/pom.xml @@ -9,6 +9,6 @@ ../ io.cloudbeaver.ce.drivers.feature - 1.0.129-SNAPSHOT + 1.0.130-SNAPSHOT eclipse-feature diff --git a/server/features/io.cloudbeaver.product.ce.feature/feature.xml b/server/features/io.cloudbeaver.product.ce.feature/feature.xml index 2859ff7450..284670b63a 100644 --- a/server/features/io.cloudbeaver.product.ce.feature/feature.xml +++ b/server/features/io.cloudbeaver.product.ce.feature/feature.xml @@ -2,7 +2,7 @@ diff --git a/server/features/io.cloudbeaver.product.ce.feature/pom.xml b/server/features/io.cloudbeaver.product.ce.feature/pom.xml index b711e83dba..0b891199c2 100644 --- a/server/features/io.cloudbeaver.product.ce.feature/pom.xml +++ b/server/features/io.cloudbeaver.product.ce.feature/pom.xml @@ -10,7 +10,7 @@ ../ io.cloudbeaver.product.ce.feature - 24.2.1-SNAPSHOT + 24.2.2-SNAPSHOT eclipse-feature diff --git a/server/features/io.cloudbeaver.server.feature/feature.xml b/server/features/io.cloudbeaver.server.feature/feature.xml index e3873e6d98..159f75d39a 100644 --- a/server/features/io.cloudbeaver.server.feature/feature.xml +++ b/server/features/io.cloudbeaver.server.feature/feature.xml @@ -2,7 +2,7 @@ diff --git a/server/features/io.cloudbeaver.server.feature/pom.xml b/server/features/io.cloudbeaver.server.feature/pom.xml index d1eda2207a..3b8fb58670 100644 --- a/server/features/io.cloudbeaver.server.feature/pom.xml +++ b/server/features/io.cloudbeaver.server.feature/pom.xml @@ -10,6 +10,6 @@ ../ io.cloudbeaver.server.feature - 24.2.1-SNAPSHOT + 24.2.2-SNAPSHOT eclipse-feature diff --git a/server/features/io.cloudbeaver.ws.feature/feature.xml b/server/features/io.cloudbeaver.ws.feature/feature.xml index 7e39d57fb1..714ab2baf7 100644 --- a/server/features/io.cloudbeaver.ws.feature/feature.xml +++ b/server/features/io.cloudbeaver.ws.feature/feature.xml @@ -2,7 +2,7 @@ diff --git a/server/features/io.cloudbeaver.ws.feature/pom.xml b/server/features/io.cloudbeaver.ws.feature/pom.xml index de5b10caaf..36705b3d43 100644 --- a/server/features/io.cloudbeaver.ws.feature/pom.xml +++ b/server/features/io.cloudbeaver.ws.feature/pom.xml @@ -10,6 +10,6 @@ ../ io.cloudbeaver.ws.feature - 1.0.59-SNAPSHOT + 1.0.60-SNAPSHOT eclipse-feature diff --git a/server/pom.xml b/server/pom.xml index 840742f3a6..4337a2507b 100644 --- a/server/pom.xml +++ b/server/pom.xml @@ -19,7 +19,7 @@ CloudBeaver CE - 24.2.1 + 24.2.2 diff --git a/server/product/web-server/CloudbeaverServer.product b/server/product/web-server/CloudbeaverServer.product index 72baeb5698..179c684197 100644 --- a/server/product/web-server/CloudbeaverServer.product +++ b/server/product/web-server/CloudbeaverServer.product @@ -2,7 +2,7 @@ diff --git a/server/product/web-server/pom.xml b/server/product/web-server/pom.xml index 22f71d98a5..ef175dce7d 100644 --- a/server/product/web-server/pom.xml +++ b/server/product/web-server/pom.xml @@ -9,7 +9,7 @@ 1.0.0-SNAPSHOT ../../ - 24.2.1-SNAPSHOT + 24.2.2-SNAPSHOT web-server eclipse-repository Cloudbeaver Server Product