Skip to content

Commit

Permalink
Merge pull request #738 from FgForrest/737-preconfigured-connection-i…
Browse files Browse the repository at this point in the history
…n-embedded-evitalab-are-sometimes-not-loaded

fix(#737): passing data to embedded evitaLab through unreliable cookies
  • Loading branch information
lukashornych authored Nov 7, 2024
2 parents 5af649a + 8d07375 commit fc3b876
Show file tree
Hide file tree
Showing 11 changed files with 256 additions and 195 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,11 @@
import com.linecorp.armeria.common.HttpHeaderNames;
import com.linecorp.armeria.common.HttpRequest;
import com.linecorp.armeria.common.HttpResponse;
import com.linecorp.armeria.common.HttpStatus;
import com.linecorp.armeria.common.QueryParamsBuilder;
import com.linecorp.armeria.server.HttpService;
import com.linecorp.armeria.server.ServiceRequestContext;
import com.linecorp.armeria.server.file.HttpFile;
import io.evitadb.externalApi.lab.configuration.GuiConfig;
import io.evitadb.externalApi.lab.configuration.LabConfig;
import io.evitadb.externalApi.lab.gui.dto.EvitaDBConnection;

Expand All @@ -53,9 +54,10 @@ public class GuiHandler implements HttpService {

private static final Encoder BASE_64_ENCODER = Base64.getEncoder();

private static final String EVITALAB_SERVER_NAME_COOKIE = "evitalab_servername";
private static final String EVITALAB_READONLY_COOKIE = "evitalab_readonly";
private static final String EVITALAB_PRECONFIGURED_CONNECTIONS_COOKIE = "evitalab_pconnections";
private static final String EVITALAB_DATA_SET_PARAM_NAME = "evitalab";
private static final String EVITALAB_SERVER_NAME_PARAM_NAME = "evitalab-server-name";
private static final String EVITALAB_READONLY_PARAM_NAME = "evitalab-readonly";
private static final String EVITALAB_PRECONFIGURED_CONNECTIONS_PARAM_NAME = "evitalab-pconnections";

private static final Pattern ASSETS_PATTERN = Pattern.compile("/assets/([a-zA-Z0-9\\-]+/)*[a-zA-Z0-9\\-]+\\.[a-z0-9]+");
private static final Pattern ROOT_ASSETS_PATTERN = Pattern.compile("(/logo)?/[a-zA-Z0-9\\-]+\\.[a-z0-9]+");
Expand Down Expand Up @@ -107,9 +109,22 @@ private HttpResponse serveRoot(@Nonnull ServiceRequestContext ctx,
@Nonnull HttpRequest req,
@Nonnull ClassLoader classLoader,
@Nonnull Path fsPath) throws Exception {
passServerName(ctx);
passReadOnlyFlag(ctx);
passPreconfiguredEvitaDBConnections(ctx);
final boolean labDataSetParamValue = isLabDataSet(ctx);
if (!labDataSetParamValue) {
final QueryParamsBuilder paramsWithLabData = ctx.queryParams().toBuilder();
passLabDataSet(paramsWithLabData);
passServerName(paramsWithLabData);
passReadOnlyFlag(paramsWithLabData);
passPreconfiguredEvitaDBConnections(paramsWithLabData);

final String newQueryString = paramsWithLabData.toQueryString();

// pass data to lab by redirecting the browser to new URL with the data
return HttpResponse.builder()
.status(HttpStatus.SEE_OTHER)
.header(HttpHeaderNames.LOCATION, ctx.path() + "?" + newQueryString)
.build();
}

return HttpFile.of(
classLoader,
Expand Down Expand Up @@ -147,36 +162,51 @@ private static String createJarResourceLocationWithForwardSlashes(@Nonnull Path
return path.toString().replace("\\", "/");
}

private void passServerName(@Nonnull ServiceRequestContext ctx) {
ctx.addAdditionalResponseHeader(
HttpHeaderNames.SET_COOKIE,
createCookie(EVITALAB_SERVER_NAME_COOKIE, serverName)
);
@Nonnull
private static Boolean isLabDataSet(@Nonnull ServiceRequestContext ctx) {
return Boolean.parseBoolean(ctx.queryParam(EVITALAB_DATA_SET_PARAM_NAME));
}

/**
* Sends a {@link #EVITALAB_READONLY_COOKIE} cookie to the evitaLab with {@link GuiConfig#isReadOnly()} flag.
* Creates a {@link #EVITALAB_DATA_SET_PARAM_NAME} param to the evitaLab as system property to indicate that lab data
* were set and should not be set again.
*/
private void passLabDataSet(@Nonnull QueryParamsBuilder params) {
params.add(EVITALAB_DATA_SET_PARAM_NAME, Boolean.TRUE.toString());
}

/**
* Passes a {@link #EVITALAB_SERVER_NAME_PARAM_NAME} param to the evitaLab as system property to specify source server.
*/
private void passServerName(@Nonnull QueryParamsBuilder params) {
passEncodedParam(params, EVITALAB_SERVER_NAME_PARAM_NAME, serverName);
}

/**
* Passes a {@link #EVITALAB_READONLY_PARAM_NAME} param to the evitaLab as system property to specify
* in which mode should evitaLab run.
* If true, the evitaLab GUI will be in read-only mode.
*/
private void passReadOnlyFlag(@Nonnull ServiceRequestContext ctx) {
ctx.addAdditionalResponseHeader(
HttpHeaderNames.SET_COOKIE,
createCookie(EVITALAB_READONLY_COOKIE, String.valueOf(labConfig.getGui().isReadOnly()))
);
private void passReadOnlyFlag(@Nonnull QueryParamsBuilder params) {
passEncodedParam(params, EVITALAB_READONLY_PARAM_NAME, String.valueOf(labConfig.getGui().isReadOnly()));
}

/**
* Sends a {@link #EVITALAB_PRECONFIGURED_CONNECTIONS_COOKIE} cookie to the evitaLab with preconfigured
* Passes a {@link #EVITALAB_PRECONFIGURED_CONNECTIONS_PARAM_NAME} param to the evitaLab as system property with preconfigured
* evitaDB connections.
*/
private void passPreconfiguredEvitaDBConnections(@Nonnull ServiceRequestContext ctx) throws IOException {
private void passPreconfiguredEvitaDBConnections(@Nonnull QueryParamsBuilder params) throws IOException {
final List<EvitaDBConnection> preconfiguredConnections = resolvePreconfiguredEvitaDBConnections();
final String serializedSelfConnection = objectMapper.writeValueAsString(preconfiguredConnections);

ctx.addAdditionalResponseHeader(
HttpHeaderNames.SET_COOKIE,
createCookie(EVITALAB_PRECONFIGURED_CONNECTIONS_COOKIE, serializedSelfConnection)
);
passEncodedParam(params, EVITALAB_PRECONFIGURED_CONNECTIONS_PARAM_NAME, serializedSelfConnection);
}

/**
* Passes a param to the evitaLab as system property. Its value is encoded with Base64
*/
private void passEncodedParam(@Nonnull QueryParamsBuilder params, @Nonnull String name, @Nonnull String value) {
params.add(name, BASE_64_ENCODER.encodeToString(value.getBytes(StandardCharsets.UTF_8)));
}

@Nonnull
Expand All @@ -196,9 +226,4 @@ private List<EvitaDBConnection> resolvePreconfiguredEvitaDBConnections() {
}
return preconfiguredConnections;
}

@Nonnull
private static String createCookie(@Nonnull String name, @Nonnull String value) {
return name + "=" + BASE_64_ENCODER.encodeToString(value.getBytes(StandardCharsets.UTF_8)) + ";Max-Age=30;SameSite=Strict";
}
}

This file was deleted.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Large diffs are not rendered by default.

This file was deleted.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit fc3b876

Please sign in to comment.