Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ public InstanceInfo instanceInfo() {
// Executable-based

public boolean isConsole() {
return Executable.ID_CONSOLE.equals(executableId());
return Executable.CONSOLE_ID.equals(executableId());
}

public boolean isAutomaticScript() {
Expand Down
4 changes: 3 additions & 1 deletion core/src/main/java/dev/vml/es/acm/core/code/Executable.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@

public interface Executable extends Serializable {

String ID_CONSOLE = "console";
String CONSOLE_ID = "console";

String CONSOLE_SCRIPT_PATH = "/conf/acm/settings/script/template/core/console.groovy";

String getId();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ private ExecutableUtils() {
}

public static String nameById(String id) {
if (Executable.ID_CONSOLE.equals(id)) {
if (Executable.CONSOLE_ID.equals(id)) {
return "Console";
}
if (StringUtils.startsWith(id, ScriptType.AUTOMATIC.root() + "/")) {
Expand All @@ -30,7 +30,7 @@ public static String nameById(String id) {
}

public static boolean isIdExplicit(String id) {
return Executable.ID_CONSOLE.equals(id) || StringUtils.startsWith(id, ScriptRepository.ROOT + "/");
return Executable.CONSOLE_ID.equals(id) || StringUtils.startsWith(id, ScriptRepository.ROOT + "/");
}

public static boolean isUserExplicit(String userId) {
Expand Down
18 changes: 18 additions & 0 deletions core/src/main/java/dev/vml/es/acm/core/code/Executor.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
import dev.vml.es.acm.core.osgi.InstanceInfo;
import dev.vml.es.acm.core.osgi.OsgiContext;
import dev.vml.es.acm.core.repo.Locker;
import dev.vml.es.acm.core.script.Script;
import dev.vml.es.acm.core.script.ScriptRepository;
import dev.vml.es.acm.core.script.ScriptType;
import dev.vml.es.acm.core.util.DateUtils;
import dev.vml.es.acm.core.util.ResolverUtils;
import dev.vml.es.acm.core.util.StringUtil;
Expand Down Expand Up @@ -130,6 +133,21 @@ public void onEvent(Event event) {
}
}

public boolean authorize(Executable executable, String userId) {
return ResolverUtils.queryContentResolver(resolverFactory, userId, resolver -> {
return authorize(executable, resolver);
});
}

public boolean authorize(Executable executable, ResourceResolver resolver) {
String scriptPath = executable.getId();
if (Executable.CONSOLE_ID.equals(executable.getId())) {
scriptPath = Executable.CONSOLE_SCRIPT_PATH;
}
ScriptRepository repository = new ScriptRepository(resolver);
return repository.read(scriptPath).isPresent();
}

public ExecutionContext createContext(
String id,
String userId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ protected void doPost(SlingHttpServletRequest request, SlingHttpServletResponse
}

Code code = input.getCode();
if (!executor.authorize(code, request.getResourceResolver())) {
respondJson(response, forbidden(String.format("Code from '%s' is not authorized!", code.getId())));
return;
}

ExecutionMode mode = ExecutionMode.of(input.getMode()).orElse(null);
if (mode == null) {
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ protected void doPost(SlingHttpServletRequest request, SlingHttpServletResponse
}

Code code = input.getCode();
if (!executor.authorize(code, request.getResourceResolver())) {
respondJson(response, forbidden(String.format("Code from '%s' is not authorized!", code.getId())));
return;
}

try (ExecutionContext context = executor.createContext(
ExecutionId.generate(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,17 @@
import static dev.vml.es.acm.core.util.ServletResult.ok;
import static dev.vml.es.acm.core.util.ServletUtils.respondJson;

import dev.vml.es.acm.core.code.Code;
import dev.vml.es.acm.core.code.Executable;
import dev.vml.es.acm.core.code.ExecutionQueue;
import dev.vml.es.acm.core.code.Executor;
import dev.vml.es.acm.core.gui.SpaSettings;
import dev.vml.es.acm.core.instance.HealthChecker;
import dev.vml.es.acm.core.instance.HealthStatus;
import dev.vml.es.acm.core.mock.MockHttpFilter;
import dev.vml.es.acm.core.mock.MockStatus;
import dev.vml.es.acm.core.osgi.InstanceInfo;
import dev.vml.es.acm.core.state.Permissions;
import dev.vml.es.acm.core.state.State;
import java.io.IOException;
import javax.servlet.Servlet;
Expand Down Expand Up @@ -51,12 +55,16 @@ public class StateServlet extends SlingAllMethodsServlet {
@Reference
private transient SpaSettings spaSettings;

@Reference
private transient Executor executor;

@Override
protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) throws IOException {
try {
HealthStatus healthStatus = healthChecker.checkStatus();
MockStatus mockStatus = mockHttpFilter.checkStatus();
State state = new State(spaSettings, healthStatus, mockStatus, instanceInfo.getSettings());
Permissions permissions = new Permissions(executor.authorize(Code.consoleMinimal(), request.getResourceResolver()));
State state = new State(spaSettings, healthStatus, mockStatus, instanceInfo.getSettings(), permissions);

respondJson(response, ok("State read successfully", state));
} catch (Exception e) {
Expand Down
16 changes: 16 additions & 0 deletions core/src/main/java/dev/vml/es/acm/core/state/Permissions.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package dev.vml.es.acm.core.state;

import java.io.Serializable;

public class Permissions implements Serializable {

private boolean console;

public Permissions(boolean console) {
this.console = console;
}

public boolean isConsole() {
return console;
}
}
10 changes: 9 additions & 1 deletion core/src/main/java/dev/vml/es/acm/core/state/State.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,19 @@ public class State implements Serializable {

private final SpaSettings spaSettings;

private final Permissions permissions;

public State(
SpaSettings spaSettings,
HealthStatus healthStatus,
MockStatus mockStatus,
InstanceSettings instanceSettings) {
InstanceSettings instanceSettings,
Permissions permissions) {
this.spaSettings = spaSettings;
this.healthStatus = healthStatus;
this.mockStatus = mockStatus;
this.instanceSettings = instanceSettings;
this.permissions = permissions;
}

public HealthStatus getHealthStatus() {
Expand All @@ -42,4 +46,8 @@ public InstanceSettings getInstanceSettings() {
public SpaSettings getSpaSettings() {
return spaSettings;
}

public Permissions getPermissions() {
return permissions;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ public static ServletResult<Void> badRequest(String message) {
return new ServletResult<>(HttpServletResponse.SC_BAD_REQUEST, message);
}

public static ServletResult<Void> forbidden(String message) {
return new ServletResult<>(HttpServletResponse.SC_FORBIDDEN, message);
}

public static ServletResult<Void> error(String message) {
return new ServletResult<>(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, message);
}
Expand Down
4 changes: 1 addition & 3 deletions ui.apps/src/main/content/jcr_root/apps/acm/api/.content.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:nt="http://www.jcp.org/jcr/nt/1.0" xmlns:rep="internal"
jcr:mixinTypes="[rep:AccessControllable]"
jcr:primaryType="nt:unstructured">
<execute-script/>
</jcr:root>
jcr:primaryType="nt:unstructured"/>

This file was deleted.

3 changes: 3 additions & 0 deletions ui.frontend/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ function App() {
role: InstanceRole.AUTHOR,
type: InstanceType.CLOUD_CONTAINER,
},
permissions: {
console: false,
},
});

const isFetching = useRef(false);
Expand Down
17 changes: 11 additions & 6 deletions ui.frontend/src/components/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,12 @@ import Home from '@spectrum-icons/workflow/Home';
import Maintenance from '@spectrum-icons/workflow/Settings';
import { useLocation } from 'react-router-dom';
import { AppLink } from '../AppLink.tsx';
import { useAppState } from '../hooks/app.ts';
import Toggle from './Toggle.tsx';

const Header = () => {
const location = useLocation();
const state = useAppState();

return (
<Flex justifyContent="center" gap="size-100" marginBottom="size-200">
Expand All @@ -18,12 +21,14 @@ const Header = () => {
<Home />
</Button>
</AppLink>
<AppLink to="/console">
<Button variant={location.pathname.startsWith('/console') ? 'accent' : 'primary'} style="outline">
<Draft />
<Text>Console</Text>
</Button>
</AppLink>
<Toggle when={state.permissions.console}>
<AppLink to="/console">
<Button variant={location.pathname.startsWith('/console') ? 'accent' : 'primary'} style="outline">
<Draft />
<Text>Console</Text>
</Button>
</AppLink>
</Toggle>
<AppLink to="/scripts">
<Button variant={location.pathname.startsWith('/scripts') ? 'accent' : 'primary'} style="outline">
<FileCode />
Expand Down
5 changes: 5 additions & 0 deletions ui.frontend/src/types/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ export type State = {
healthStatus: HealthStatus;
mockStatus: MockStatus;
instanceSettings: InstanceSettings;
permissions: Permissions;
};

export type SpaSettings = {
Expand All @@ -65,6 +66,10 @@ export type MockStatus = {
enabled: boolean;
};

export type Permissions = {
console: boolean;
};

export enum ExecutionFormat {
SUMMARY = 'SUMMARY',
FULL = 'FULL',
Expand Down