mirror of
https://github.com/xpipe-io/xpipe.git
synced 2024-09-30 00:56:56 +13:00
Add interactive check and rework api [stage]
This commit is contained in:
parent
c5608bd23c
commit
adb621dab4
16 changed files with 304 additions and 60 deletions
|
@ -3,6 +3,8 @@ package io.xpipe.app.beacon.impl;
|
||||||
import com.sun.net.httpserver.HttpExchange;
|
import com.sun.net.httpserver.HttpExchange;
|
||||||
import io.xpipe.app.util.AskpassAlert;
|
import io.xpipe.app.util.AskpassAlert;
|
||||||
import io.xpipe.app.util.SecretManager;
|
import io.xpipe.app.util.SecretManager;
|
||||||
|
import io.xpipe.app.util.SecretQueryState;
|
||||||
|
import io.xpipe.beacon.BeaconClientException;
|
||||||
import io.xpipe.beacon.api.AskpassExchange;
|
import io.xpipe.beacon.api.AskpassExchange;
|
||||||
|
|
||||||
public class AskpassExchangeImpl extends AskpassExchange {
|
public class AskpassExchangeImpl extends AskpassExchange {
|
||||||
|
@ -13,7 +15,7 @@ public class AskpassExchangeImpl extends AskpassExchange {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object handle(HttpExchange exchange, Request msg) {
|
public Object handle(HttpExchange exchange, Request msg) throws BeaconClientException {
|
||||||
if (msg.getRequest() == null) {
|
if (msg.getRequest() == null) {
|
||||||
var r = AskpassAlert.queryRaw(msg.getPrompt(), null);
|
var r = AskpassAlert.queryRaw(msg.getPrompt(), null);
|
||||||
return Response.builder().value(r.getSecret()).build();
|
return Response.builder().value(r.getSecret()).build();
|
||||||
|
@ -23,13 +25,16 @@ public class AskpassExchangeImpl extends AskpassExchange {
|
||||||
? SecretManager.getProgress(msg.getRequest(), msg.getSecretId())
|
? SecretManager.getProgress(msg.getRequest(), msg.getSecretId())
|
||||||
: SecretManager.getProgress(msg.getRequest());
|
: SecretManager.getProgress(msg.getRequest());
|
||||||
if (found.isEmpty()) {
|
if (found.isEmpty()) {
|
||||||
return Response.builder().build();
|
throw new BeaconClientException("No password was provided");
|
||||||
}
|
}
|
||||||
|
|
||||||
var p = found.get();
|
var p = found.get();
|
||||||
var secret = p.process(msg.getPrompt());
|
var secret = p.process(msg.getPrompt());
|
||||||
|
if (p.getState() != SecretQueryState.NORMAL) {
|
||||||
|
throw new BeaconClientException(SecretQueryState.toErrorMessage(p.getState()));
|
||||||
|
}
|
||||||
return Response.builder()
|
return Response.builder()
|
||||||
.value(secret != null ? secret.inPlace() : null)
|
.value(secret.inPlace())
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ public class FsScriptExchangeImpl extends FsScriptExchange {
|
||||||
var shell = AppBeaconServer.get().getCache().getShellSession(msg.getConnection());
|
var shell = AppBeaconServer.get().getCache().getShellSession(msg.getConnection());
|
||||||
var data = new String(AppBeaconServer.get().getCache().getBlob(msg.getBlob()), StandardCharsets.UTF_8);
|
var data = new String(AppBeaconServer.get().getCache().getBlob(msg.getBlob()), StandardCharsets.UTF_8);
|
||||||
var file = ScriptHelper.getExecScriptFile(shell.getControl());
|
var file = ScriptHelper.getExecScriptFile(shell.getControl());
|
||||||
shell.getControl().getShellDialect().createScriptTextFileWriteCommand(shell.getControl(), data, file.toString());
|
shell.getControl().getShellDialect().createScriptTextFileWriteCommand(shell.getControl(), data, file.toString()).execute();
|
||||||
return Response.builder().path(file).build();
|
return Response.builder().path(file).build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,12 +24,12 @@ public class ShellStartExchangeImpl extends ShellStartExchange {
|
||||||
var existing = AppBeaconServer.get().getCache().getShellSessions().stream()
|
var existing = AppBeaconServer.get().getCache().getShellSessions().stream()
|
||||||
.filter(beaconShellSession -> beaconShellSession.getEntry().equals(e))
|
.filter(beaconShellSession -> beaconShellSession.getEntry().equals(e))
|
||||||
.findFirst();
|
.findFirst();
|
||||||
if (existing.isPresent()) {
|
var control = (existing.isPresent() ? existing.get().getControl() : s.control());
|
||||||
return Response.builder().build();
|
control.setNonInteractive();
|
||||||
}
|
control.start();
|
||||||
|
if (existing.isEmpty()) {
|
||||||
var control = s.control().start();
|
|
||||||
AppBeaconServer.get().getCache().getShellSessions().add(new BeaconShellSession(e, control));
|
AppBeaconServer.get().getCache().getShellSessions().add(new BeaconShellSession(e, control));
|
||||||
return Response.builder().build();
|
}
|
||||||
|
return Response.builder().shellDialect(control.getShellDialect()).osType(control.getOsType()).osName(control.getOsName()).temp(control.getSystemTemporaryDirectory()).build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ public class AskpassAlert {
|
||||||
|
|
||||||
public static SecretQueryResult queryRaw(String prompt, InPlaceSecretValue secretValue) {
|
public static SecretQueryResult queryRaw(String prompt, InPlaceSecretValue secretValue) {
|
||||||
if (!PlatformState.initPlatformIfNeeded()) {
|
if (!PlatformState.initPlatformIfNeeded()) {
|
||||||
return new SecretQueryResult(null, true);
|
return new SecretQueryResult(null, SecretQueryState.CANCELLED);
|
||||||
}
|
}
|
||||||
|
|
||||||
AppStyle.init();
|
AppStyle.init();
|
||||||
|
@ -103,6 +103,6 @@ public class AskpassAlert {
|
||||||
return prop.getValue() != null ? prop.getValue() : InPlaceSecretValue.of("");
|
return prop.getValue() != null ? prop.getValue() : InPlaceSecretValue.of("");
|
||||||
})
|
})
|
||||||
.orElse(null);
|
.orElse(null);
|
||||||
return new SecretQueryResult(r, r == null);
|
return new SecretQueryResult(r, r == null ? SecretQueryState.CANCELLED : SecretQueryState.NORMAL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,8 +34,9 @@ public class SecretManager {
|
||||||
List<SecretQuery> suppliers,
|
List<SecretQuery> suppliers,
|
||||||
SecretQuery fallback,
|
SecretQuery fallback,
|
||||||
List<SecretQueryFilter> filters,
|
List<SecretQueryFilter> filters,
|
||||||
CountDown countDown) {
|
CountDown countDown,
|
||||||
var p = new SecretQueryProgress(request, storeId, suppliers, fallback, filters, countDown);
|
boolean interactive) {
|
||||||
|
var p = new SecretQueryProgress(request, storeId, suppliers, fallback, filters, countDown, interactive);
|
||||||
progress.add(p);
|
progress.add(p);
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
@ -55,14 +56,14 @@ public class SecretManager {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SecretValue retrieve(SecretRetrievalStrategy strategy, String prompt, UUID secretId, int sub) {
|
public static SecretValue retrieve(SecretRetrievalStrategy strategy, String prompt, UUID secretId, int sub, boolean interactive) {
|
||||||
if (!strategy.expectsQuery()) {
|
if (!strategy.expectsQuery()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
var uuid = UUID.randomUUID();
|
var uuid = UUID.randomUUID();
|
||||||
var p = expectAskpass(
|
var p = expectAskpass(
|
||||||
uuid, secretId, List.of(strategy.query()), SecretQuery.prompt(false), List.of(), CountDown.of());
|
uuid, secretId, List.of(strategy.query()), SecretQuery.prompt(false), List.of(), CountDown.of(), interactive);
|
||||||
p.preAdvance(sub);
|
p.preAdvance(sub);
|
||||||
var r = p.process(prompt);
|
var r = p.process(prompt);
|
||||||
completeRequest(uuid);
|
completeRequest(uuid);
|
||||||
|
|
|
@ -32,13 +32,13 @@ public interface SecretQuery {
|
||||||
|
|
||||||
var inPlace = found.get().getSecret().inPlace();
|
var inPlace = found.get().getSecret().inPlace();
|
||||||
var r = AskpassAlert.queryRaw(prompt, inPlace);
|
var r = AskpassAlert.queryRaw(prompt, inPlace);
|
||||||
return r.isCancelled() ? Optional.of(r) : found;
|
return r.getState() != SecretQueryState.NORMAL ? Optional.of(r) : found;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SecretQueryResult query(String prompt) {
|
public SecretQueryResult query(String prompt) {
|
||||||
var r = original.query(prompt);
|
var r = original.query(prompt);
|
||||||
if (r.isCancelled()) {
|
if (r.getState() != SecretQueryState.NORMAL) {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,7 +96,7 @@ public interface SecretQuery {
|
||||||
|
|
||||||
default Optional<SecretQueryResult> retrieveCache(String prompt, SecretReference reference) {
|
default Optional<SecretQueryResult> retrieveCache(String prompt, SecretReference reference) {
|
||||||
var r = SecretManager.get(reference);
|
var r = SecretManager.get(reference);
|
||||||
return r.map(secretValue -> new SecretQueryResult(secretValue, false));
|
return r.map(secretValue -> new SecretQueryResult(secretValue, SecretQueryState.NORMAL));
|
||||||
}
|
}
|
||||||
|
|
||||||
SecretQueryResult query(String prompt);
|
SecretQueryResult query(String prompt);
|
||||||
|
|
|
@ -22,7 +22,8 @@ public class SecretQueryProgress {
|
||||||
private final List<SecretQueryFilter> filters;
|
private final List<SecretQueryFilter> filters;
|
||||||
private final List<String> seenPrompts;
|
private final List<String> seenPrompts;
|
||||||
private final CountDown countDown;
|
private final CountDown countDown;
|
||||||
private boolean requestCancelled;
|
private final boolean interactive;
|
||||||
|
private SecretQueryState state = SecretQueryState.NORMAL;
|
||||||
|
|
||||||
public SecretQueryProgress(
|
public SecretQueryProgress(
|
||||||
@NonNull UUID requestId,
|
@NonNull UUID requestId,
|
||||||
|
@ -30,13 +31,16 @@ public class SecretQueryProgress {
|
||||||
@NonNull List<SecretQuery> suppliers,
|
@NonNull List<SecretQuery> suppliers,
|
||||||
@NonNull SecretQuery fallback,
|
@NonNull SecretQuery fallback,
|
||||||
@NonNull List<SecretQueryFilter> filters,
|
@NonNull List<SecretQueryFilter> filters,
|
||||||
@NonNull CountDown countDown) {
|
@NonNull CountDown countDown,
|
||||||
|
boolean interactive
|
||||||
|
) {
|
||||||
this.requestId = requestId;
|
this.requestId = requestId;
|
||||||
this.storeId = storeId;
|
this.storeId = storeId;
|
||||||
this.suppliers = new ArrayList<>(suppliers);
|
this.suppliers = new ArrayList<>(suppliers);
|
||||||
this.fallback = fallback;
|
this.fallback = fallback;
|
||||||
this.filters = filters;
|
this.filters = filters;
|
||||||
this.countDown = countDown;
|
this.countDown = countDown;
|
||||||
|
this.interactive = interactive;
|
||||||
this.seenPrompts = new ArrayList<>();
|
this.seenPrompts = new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,7 +53,7 @@ public class SecretQueryProgress {
|
||||||
|
|
||||||
public SecretValue process(String prompt) {
|
public SecretValue process(String prompt) {
|
||||||
// Cancel early
|
// Cancel early
|
||||||
if (requestCancelled) {
|
if (state != SecretQueryState.NORMAL) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,11 +71,18 @@ public class SecretQueryProgress {
|
||||||
|
|
||||||
var firstSeenIndex = seenPrompts.indexOf(prompt);
|
var firstSeenIndex = seenPrompts.indexOf(prompt);
|
||||||
if (firstSeenIndex >= suppliers.size()) {
|
if (firstSeenIndex >= suppliers.size()) {
|
||||||
|
// Check whether we can have user inputs
|
||||||
|
if (!interactive && fallback.requiresUserInteraction()) {
|
||||||
|
state = SecretQueryState.NON_INTERACTIVE;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
countDown.pause();
|
countDown.pause();
|
||||||
var r = fallback.query(prompt);
|
var r = fallback.query(prompt);
|
||||||
countDown.resume();
|
countDown.resume();
|
||||||
if (r.isCancelled()) {
|
|
||||||
requestCancelled = true;
|
if (r.getState() != SecretQueryState.NORMAL) {
|
||||||
|
state = r.getState();
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return r.getSecret();
|
return r.getSecret();
|
||||||
|
@ -82,6 +93,12 @@ public class SecretQueryProgress {
|
||||||
var shouldCache = shouldCache(sup, prompt);
|
var shouldCache = shouldCache(sup, prompt);
|
||||||
var wasLastPrompt = firstSeenIndex == seenPrompts.size() - 1;
|
var wasLastPrompt = firstSeenIndex == seenPrompts.size() - 1;
|
||||||
|
|
||||||
|
// Check whether we can have user inputs
|
||||||
|
if (!interactive && sup.requiresUserInteraction()) {
|
||||||
|
state = SecretQueryState.NON_INTERACTIVE;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
// Clear cache if secret was wrong/queried again
|
// Clear cache if secret was wrong/queried again
|
||||||
// Check whether this is actually the last prompt seen as it might happen that
|
// Check whether this is actually the last prompt seen as it might happen that
|
||||||
// previous prompts get rolled back again when one further down is wrong
|
// previous prompts get rolled back again when one further down is wrong
|
||||||
|
@ -91,7 +108,7 @@ public class SecretQueryProgress {
|
||||||
|
|
||||||
// If we supplied a wrong secret and cannot retry, cancel the entire request
|
// If we supplied a wrong secret and cannot retry, cancel the entire request
|
||||||
if (seenBefore && wasLastPrompt && !sup.retryOnFail()) {
|
if (seenBefore && wasLastPrompt && !sup.retryOnFail()) {
|
||||||
requestCancelled = true;
|
state = SecretQueryState.FIXED_SECRET_WRONG;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,8 +117,8 @@ public class SecretQueryProgress {
|
||||||
var cached = sup.retrieveCache(prompt, ref);
|
var cached = sup.retrieveCache(prompt, ref);
|
||||||
countDown.resume();
|
countDown.resume();
|
||||||
if (cached.isPresent()) {
|
if (cached.isPresent()) {
|
||||||
if (cached.get().isCancelled()) {
|
if (cached.get().getState() != SecretQueryState.NORMAL) {
|
||||||
requestCancelled = true;
|
state = cached.get().getState();
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,8 +130,8 @@ public class SecretQueryProgress {
|
||||||
var r = sup.query(prompt);
|
var r = sup.query(prompt);
|
||||||
countDown.resume();
|
countDown.resume();
|
||||||
|
|
||||||
if (r.isCancelled()) {
|
if (r.getState() != SecretQueryState.NORMAL) {
|
||||||
requestCancelled = true;
|
state = r.getState();
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,5 +8,5 @@ import lombok.Value;
|
||||||
public class SecretQueryResult {
|
public class SecretQueryResult {
|
||||||
|
|
||||||
SecretValue secret;
|
SecretValue secret;
|
||||||
boolean cancelled;
|
SecretQueryState state;
|
||||||
}
|
}
|
||||||
|
|
33
app/src/main/java/io/xpipe/app/util/SecretQueryState.java
Normal file
33
app/src/main/java/io/xpipe/app/util/SecretQueryState.java
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
package io.xpipe.app.util;
|
||||||
|
|
||||||
|
public enum SecretQueryState {
|
||||||
|
NORMAL,
|
||||||
|
CANCELLED,
|
||||||
|
NON_INTERACTIVE,
|
||||||
|
FIXED_SECRET_WRONG,
|
||||||
|
RETRIEVAL_FAILURE;
|
||||||
|
|
||||||
|
public static String toErrorMessage(SecretQueryState s) {
|
||||||
|
if (s == null) {
|
||||||
|
return "None";
|
||||||
|
}
|
||||||
|
|
||||||
|
return switch (s) {
|
||||||
|
case NORMAL -> {
|
||||||
|
yield "None";
|
||||||
|
}
|
||||||
|
case CANCELLED -> {
|
||||||
|
yield "Operation was cancelled";
|
||||||
|
}
|
||||||
|
case NON_INTERACTIVE -> {
|
||||||
|
yield "Session is not interactive but required user input";
|
||||||
|
}
|
||||||
|
case FIXED_SECRET_WRONG -> {
|
||||||
|
yield "Provided secret is wrong";
|
||||||
|
}
|
||||||
|
case RETRIEVAL_FAILURE -> {
|
||||||
|
yield "Failed to retrieve secret";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -60,7 +60,7 @@ public interface SecretRetrievalStrategy {
|
||||||
@Override
|
@Override
|
||||||
public SecretQueryResult query(String prompt) {
|
public SecretQueryResult query(String prompt) {
|
||||||
return new SecretQueryResult(
|
return new SecretQueryResult(
|
||||||
value != null ? value.getInternalSecret() : InPlaceSecretValue.of(""), false);
|
value != null ? value.getInternalSecret() : InPlaceSecretValue.of(""), SecretQueryState.NORMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -125,7 +125,7 @@ public interface SecretRetrievalStrategy {
|
||||||
public SecretQueryResult query(String prompt) {
|
public SecretQueryResult query(String prompt) {
|
||||||
var cmd = AppPrefs.get().passwordManagerString(key);
|
var cmd = AppPrefs.get().passwordManagerString(key);
|
||||||
if (cmd == null) {
|
if (cmd == null) {
|
||||||
return new SecretQueryResult(null, true);
|
return new SecretQueryResult(null, SecretQueryState.RETRIEVAL_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
String r;
|
String r;
|
||||||
|
@ -134,7 +134,7 @@ public interface SecretRetrievalStrategy {
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
ErrorEvent.fromThrowable("Unable to retrieve password with command " + cmd, ex)
|
ErrorEvent.fromThrowable("Unable to retrieve password with command " + cmd, ex)
|
||||||
.handle();
|
.handle();
|
||||||
return new SecretQueryResult(null, true);
|
return new SecretQueryResult(null, SecretQueryState.RETRIEVAL_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (r.lines().count() > 1 || r.isBlank()) {
|
if (r.lines().count() > 1 || r.isBlank()) {
|
||||||
|
@ -145,7 +145,7 @@ public interface SecretRetrievalStrategy {
|
||||||
+ " you will have to change the command and/or password key."));
|
+ " you will have to change the command and/or password key."));
|
||||||
}
|
}
|
||||||
|
|
||||||
return new SecretQueryResult(InPlaceSecretValue.of(r), false);
|
return new SecretQueryResult(InPlaceSecretValue.of(r), SecretQueryState.NORMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -180,11 +180,11 @@ public interface SecretRetrievalStrategy {
|
||||||
@Override
|
@Override
|
||||||
public SecretQueryResult query(String prompt) {
|
public SecretQueryResult query(String prompt) {
|
||||||
try (var cc = new LocalStore().control().command(command).start()) {
|
try (var cc = new LocalStore().control().command(command).start()) {
|
||||||
return new SecretQueryResult(InPlaceSecretValue.of(cc.readStdoutOrThrow()), false);
|
return new SecretQueryResult(InPlaceSecretValue.of(cc.readStdoutOrThrow()), SecretQueryState.NORMAL);
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
ErrorEvent.fromThrowable("Unable to retrieve password with command " + command, ex)
|
ErrorEvent.fromThrowable("Unable to retrieve password with command " + command, ex)
|
||||||
.handle();
|
.handle();
|
||||||
return new SecretQueryResult(null, true);
|
return new SecretQueryResult(null, SecretQueryState.RETRIEVAL_FAILURE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,6 @@ You can get started by either using this page as an API reference or alternative
|
||||||
<a download href="/openapi.yaml" style="font-size: 20px">OpenAPI .yaml specification</a>
|
<a download href="/openapi.yaml" style="font-size: 20px">OpenAPI .yaml specification</a>
|
||||||
|
|
||||||
The XPipe application will start up an HTTP server that can be used to send requests.
|
The XPipe application will start up an HTTP server that can be used to send requests.
|
||||||
You can change the port of it in the settings menu.
|
|
||||||
Note that this server is HTTP-only for now as it runs only on localhost. HTTPS requests are not accepted.
|
Note that this server is HTTP-only for now as it runs only on localhost. HTTPS requests are not accepted.
|
||||||
|
|
||||||
This allows you to programmatically manage remote systems.
|
This allows you to programmatically manage remote systems.
|
||||||
|
@ -104,8 +103,8 @@ Note that for development you can also turn off the required authentication in t
|
||||||
|Status|Meaning|Description|Schema|
|
|Status|Meaning|Description|Schema|
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|The handshake was successful. The returned token can be used for authentication in this session. The token is valid as long as XPipe is running.|[HandshakeResponse](#schemahandshakeresponse)|
|
|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|The handshake was successful. The returned token can be used for authentication in this session. The token is valid as long as XPipe is running.|[HandshakeResponse](#schemahandshakeresponse)|
|
||||||
|400|[Bad Request](https://tools.ietf.org/html/rfc7231#section-6.5.1)|Bad request. Please check error message and your parameters.|None|
|
|400|[Bad Request](https://tools.ietf.org/html/rfc7231#section-6.5.1)|Bad request. Please check error message and your parameters.|[ClientErrorResponse](#schemaclienterrorresponse)|
|
||||||
|500|[Internal Server Error](https://tools.ietf.org/html/rfc7231#section-6.6.1)|Internal error.|None|
|
|500|[Internal Server Error](https://tools.ietf.org/html/rfc7231#section-6.6.1)|Internal error.|[ServerErrorResponse](#schemaservererrorresponse)|
|
||||||
|
|
||||||
<aside class="success">
|
<aside class="success">
|
||||||
This operation does not require authentication
|
This operation does not require authentication
|
||||||
|
@ -305,16 +304,24 @@ All matching is case insensitive.
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
> 400 Response
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"message": "string"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
<h3 id="query-connections-responses">Responses</h3>
|
<h3 id="query-connections-responses">Responses</h3>
|
||||||
|
|
||||||
|Status|Meaning|Description|Schema|
|
|Status|Meaning|Description|Schema|
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|The query was successful. The body contains all matched connections.|[ConnectionQueryResponse](#schemaconnectionqueryresponse)|
|
|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|The query was successful. The body contains all matched connections.|[ConnectionQueryResponse](#schemaconnectionqueryresponse)|
|
||||||
|400|[Bad Request](https://tools.ietf.org/html/rfc7231#section-6.5.1)|Bad request. Please check error message and your parameters.|None|
|
|400|[Bad Request](https://tools.ietf.org/html/rfc7231#section-6.5.1)|Bad request. Please check error message and your parameters.|[ClientErrorResponse](#schemaclienterrorresponse)|
|
||||||
|401|[Unauthorized](https://tools.ietf.org/html/rfc7235#section-3.1)|Authorization failed. Please supply a `Bearer` token via the `Authorization` header.|None|
|
|401|[Unauthorized](https://tools.ietf.org/html/rfc7235#section-3.1)|Authorization failed. Please supply a `Bearer` token via the `Authorization` header.|None|
|
||||||
|403|[Forbidden](https://tools.ietf.org/html/rfc7231#section-6.5.3)|Authorization failed. Please supply a valid `Bearer` token via the `Authorization` header.|None|
|
|403|[Forbidden](https://tools.ietf.org/html/rfc7231#section-6.5.3)|Authorization failed. Please supply a valid `Bearer` token via the `Authorization` header.|None|
|
||||||
|404|[Not Found](https://tools.ietf.org/html/rfc7231#section-6.5.4)|The requested resource could not be found.|None|
|
|404|[Not Found](https://tools.ietf.org/html/rfc7231#section-6.5.4)|The requested resource could not be found.|None|
|
||||||
|500|[Internal Server Error](https://tools.ietf.org/html/rfc7231#section-6.6.1)|Internal error.|None|
|
|500|[Internal Server Error](https://tools.ietf.org/html/rfc7231#section-6.6.1)|Internal error.|[ServerErrorResponse](#schemaservererrorresponse)|
|
||||||
|
|
||||||
<aside class="warning">
|
<aside class="warning">
|
||||||
To perform this operation, you must be authenticated by means of one of the following methods:
|
To perform this operation, you must be authenticated by means of one of the following methods:
|
||||||
|
@ -463,16 +470,26 @@ These errors will be returned with the HTTP return code 500.
|
||||||
|---|---|---|---|---|
|
|---|---|---|---|---|
|
||||||
|body|body|[ShellStartRequest](#schemashellstartrequest)|true|none|
|
|body|body|[ShellStartRequest](#schemashellstartrequest)|true|none|
|
||||||
|
|
||||||
|
> Example responses
|
||||||
|
|
||||||
|
> 400 Response
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"message": "string"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
<h3 id="start-shell-connection-responses">Responses</h3>
|
<h3 id="start-shell-connection-responses">Responses</h3>
|
||||||
|
|
||||||
|Status|Meaning|Description|Schema|
|
|Status|Meaning|Description|Schema|
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|The operation was successful. The shell session was started.|None|
|
|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|The operation was successful. The shell session was started.|None|
|
||||||
|400|[Bad Request](https://tools.ietf.org/html/rfc7231#section-6.5.1)|Bad request. Please check error message and your parameters.|None|
|
|400|[Bad Request](https://tools.ietf.org/html/rfc7231#section-6.5.1)|Bad request. Please check error message and your parameters.|[ClientErrorResponse](#schemaclienterrorresponse)|
|
||||||
|401|[Unauthorized](https://tools.ietf.org/html/rfc7235#section-3.1)|Authorization failed. Please supply a `Bearer` token via the `Authorization` header.|None|
|
|401|[Unauthorized](https://tools.ietf.org/html/rfc7235#section-3.1)|Authorization failed. Please supply a `Bearer` token via the `Authorization` header.|None|
|
||||||
|403|[Forbidden](https://tools.ietf.org/html/rfc7231#section-6.5.3)|Authorization failed. Please supply a valid `Bearer` token via the `Authorization` header.|None|
|
|403|[Forbidden](https://tools.ietf.org/html/rfc7231#section-6.5.3)|Authorization failed. Please supply a valid `Bearer` token via the `Authorization` header.|None|
|
||||||
|404|[Not Found](https://tools.ietf.org/html/rfc7231#section-6.5.4)|The requested resource could not be found.|None|
|
|404|[Not Found](https://tools.ietf.org/html/rfc7231#section-6.5.4)|The requested resource could not be found.|None|
|
||||||
|500|[Internal Server Error](https://tools.ietf.org/html/rfc7231#section-6.6.1)|Internal error.|None|
|
|500|[Internal Server Error](https://tools.ietf.org/html/rfc7231#section-6.6.1)|Internal error.|[ServerErrorResponse](#schemaservererrorresponse)|
|
||||||
|
|
||||||
<aside class="warning">
|
<aside class="warning">
|
||||||
To perform this operation, you must be authenticated by means of one of the following methods:
|
To perform this operation, you must be authenticated by means of one of the following methods:
|
||||||
|
@ -489,6 +506,7 @@ const inputBody = '{
|
||||||
}';
|
}';
|
||||||
const headers = {
|
const headers = {
|
||||||
'Content-Type':'application/json',
|
'Content-Type':'application/json',
|
||||||
|
'Accept':'application/json',
|
||||||
'Authorization':'Bearer {access-token}'
|
'Authorization':'Bearer {access-token}'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -510,6 +528,7 @@ fetch('http://localhost:21723/shell/start',
|
||||||
import requests
|
import requests
|
||||||
headers = {
|
headers = {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
|
'Accept': 'application/json',
|
||||||
'Authorization': 'Bearer {access-token}'
|
'Authorization': 'Bearer {access-token}'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -531,6 +550,7 @@ var request = HttpRequest
|
||||||
.newBuilder()
|
.newBuilder()
|
||||||
.uri(uri)
|
.uri(uri)
|
||||||
.header("Content-Type", "application/json")
|
.header("Content-Type", "application/json")
|
||||||
|
.header("Accept", "application/json")
|
||||||
.header("Authorization", "Bearer {access-token}")
|
.header("Authorization", "Bearer {access-token}")
|
||||||
.POST(HttpRequest.BodyPublishers.ofString("""
|
.POST(HttpRequest.BodyPublishers.ofString("""
|
||||||
{
|
{
|
||||||
|
@ -556,6 +576,7 @@ func main() {
|
||||||
|
|
||||||
headers := map[string][]string{
|
headers := map[string][]string{
|
||||||
"Content-Type": []string{"application/json"},
|
"Content-Type": []string{"application/json"},
|
||||||
|
"Accept": []string{"application/json"},
|
||||||
"Authorization": []string{"Bearer {access-token}"},
|
"Authorization": []string{"Bearer {access-token}"},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -573,7 +594,7 @@ func main() {
|
||||||
```shell
|
```shell
|
||||||
# You can also use wget
|
# You can also use wget
|
||||||
curl -X POST http://localhost:21723/shell/start \
|
curl -X POST http://localhost:21723/shell/start \
|
||||||
-H 'Content-Type: application/json' \ -H 'Authorization: Bearer {access-token}' \
|
-H 'Content-Type: application/json' \ -H 'Accept: application/json' \ -H 'Authorization: Bearer {access-token}' \
|
||||||
--data '
|
--data '
|
||||||
{
|
{
|
||||||
"connection": "f0ec68aa-63f5-405c-b178-9a4454556d6b"
|
"connection": "f0ec68aa-63f5-405c-b178-9a4454556d6b"
|
||||||
|
@ -609,16 +630,26 @@ If the shell is busy or stuck, you might have to work with timeouts to account f
|
||||||
|---|---|---|---|---|
|
|---|---|---|---|---|
|
||||||
|body|body|[ShellStopRequest](#schemashellstoprequest)|true|none|
|
|body|body|[ShellStopRequest](#schemashellstoprequest)|true|none|
|
||||||
|
|
||||||
|
> Example responses
|
||||||
|
|
||||||
|
> 400 Response
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"message": "string"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
<h3 id="stop-shell-connection-responses">Responses</h3>
|
<h3 id="stop-shell-connection-responses">Responses</h3>
|
||||||
|
|
||||||
|Status|Meaning|Description|Schema|
|
|Status|Meaning|Description|Schema|
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|The operation was successful. The shell session was stopped.|None|
|
|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|The operation was successful. The shell session was stopped.|None|
|
||||||
|400|[Bad Request](https://tools.ietf.org/html/rfc7231#section-6.5.1)|Bad request. Please check error message and your parameters.|None|
|
|400|[Bad Request](https://tools.ietf.org/html/rfc7231#section-6.5.1)|Bad request. Please check error message and your parameters.|[ClientErrorResponse](#schemaclienterrorresponse)|
|
||||||
|401|[Unauthorized](https://tools.ietf.org/html/rfc7235#section-3.1)|Authorization failed. Please supply a `Bearer` token via the `Authorization` header.|None|
|
|401|[Unauthorized](https://tools.ietf.org/html/rfc7235#section-3.1)|Authorization failed. Please supply a `Bearer` token via the `Authorization` header.|None|
|
||||||
|403|[Forbidden](https://tools.ietf.org/html/rfc7231#section-6.5.3)|Authorization failed. Please supply a valid `Bearer` token via the `Authorization` header.|None|
|
|403|[Forbidden](https://tools.ietf.org/html/rfc7231#section-6.5.3)|Authorization failed. Please supply a valid `Bearer` token via the `Authorization` header.|None|
|
||||||
|404|[Not Found](https://tools.ietf.org/html/rfc7231#section-6.5.4)|The requested resource could not be found.|None|
|
|404|[Not Found](https://tools.ietf.org/html/rfc7231#section-6.5.4)|The requested resource could not be found.|None|
|
||||||
|500|[Internal Server Error](https://tools.ietf.org/html/rfc7231#section-6.6.1)|Internal error.|None|
|
|500|[Internal Server Error](https://tools.ietf.org/html/rfc7231#section-6.6.1)|Internal error.|[ServerErrorResponse](#schemaservererrorresponse)|
|
||||||
|
|
||||||
<aside class="warning">
|
<aside class="warning">
|
||||||
To perform this operation, you must be authenticated by means of one of the following methods:
|
To perform this operation, you must be authenticated by means of one of the following methods:
|
||||||
|
@ -635,6 +666,7 @@ const inputBody = '{
|
||||||
}';
|
}';
|
||||||
const headers = {
|
const headers = {
|
||||||
'Content-Type':'application/json',
|
'Content-Type':'application/json',
|
||||||
|
'Accept':'application/json',
|
||||||
'Authorization':'Bearer {access-token}'
|
'Authorization':'Bearer {access-token}'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -656,6 +688,7 @@ fetch('http://localhost:21723/shell/stop',
|
||||||
import requests
|
import requests
|
||||||
headers = {
|
headers = {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
|
'Accept': 'application/json',
|
||||||
'Authorization': 'Bearer {access-token}'
|
'Authorization': 'Bearer {access-token}'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -677,6 +710,7 @@ var request = HttpRequest
|
||||||
.newBuilder()
|
.newBuilder()
|
||||||
.uri(uri)
|
.uri(uri)
|
||||||
.header("Content-Type", "application/json")
|
.header("Content-Type", "application/json")
|
||||||
|
.header("Accept", "application/json")
|
||||||
.header("Authorization", "Bearer {access-token}")
|
.header("Authorization", "Bearer {access-token}")
|
||||||
.POST(HttpRequest.BodyPublishers.ofString("""
|
.POST(HttpRequest.BodyPublishers.ofString("""
|
||||||
{
|
{
|
||||||
|
@ -702,6 +736,7 @@ func main() {
|
||||||
|
|
||||||
headers := map[string][]string{
|
headers := map[string][]string{
|
||||||
"Content-Type": []string{"application/json"},
|
"Content-Type": []string{"application/json"},
|
||||||
|
"Accept": []string{"application/json"},
|
||||||
"Authorization": []string{"Bearer {access-token}"},
|
"Authorization": []string{"Bearer {access-token}"},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -719,7 +754,7 @@ func main() {
|
||||||
```shell
|
```shell
|
||||||
# You can also use wget
|
# You can also use wget
|
||||||
curl -X POST http://localhost:21723/shell/stop \
|
curl -X POST http://localhost:21723/shell/stop \
|
||||||
-H 'Content-Type: application/json' \ -H 'Authorization: Bearer {access-token}' \
|
-H 'Content-Type: application/json' \ -H 'Accept: application/json' \ -H 'Authorization: Bearer {access-token}' \
|
||||||
--data '
|
--data '
|
||||||
{
|
{
|
||||||
"connection": "f0ec68aa-63f5-405c-b178-9a4454556d6b"
|
"connection": "f0ec68aa-63f5-405c-b178-9a4454556d6b"
|
||||||
|
@ -777,16 +812,24 @@ However, if any other error occurs like the shell not responding or exiting unex
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
> 400 Response
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"message": "string"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
<h3 id="execute-command-in-a-shell-session-responses">Responses</h3>
|
<h3 id="execute-command-in-a-shell-session-responses">Responses</h3>
|
||||||
|
|
||||||
|Status|Meaning|Description|Schema|
|
|Status|Meaning|Description|Schema|
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|The operation was successful. The shell command finished.|[ShellExecResponse](#schemashellexecresponse)|
|
|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|The operation was successful. The shell command finished.|[ShellExecResponse](#schemashellexecresponse)|
|
||||||
|400|[Bad Request](https://tools.ietf.org/html/rfc7231#section-6.5.1)|Bad request. Please check error message and your parameters.|None|
|
|400|[Bad Request](https://tools.ietf.org/html/rfc7231#section-6.5.1)|Bad request. Please check error message and your parameters.|[ClientErrorResponse](#schemaclienterrorresponse)|
|
||||||
|401|[Unauthorized](https://tools.ietf.org/html/rfc7235#section-3.1)|Authorization failed. Please supply a `Bearer` token via the `Authorization` header.|None|
|
|401|[Unauthorized](https://tools.ietf.org/html/rfc7235#section-3.1)|Authorization failed. Please supply a `Bearer` token via the `Authorization` header.|None|
|
||||||
|403|[Forbidden](https://tools.ietf.org/html/rfc7231#section-6.5.3)|Authorization failed. Please supply a valid `Bearer` token via the `Authorization` header.|None|
|
|403|[Forbidden](https://tools.ietf.org/html/rfc7231#section-6.5.3)|Authorization failed. Please supply a valid `Bearer` token via the `Authorization` header.|None|
|
||||||
|404|[Not Found](https://tools.ietf.org/html/rfc7231#section-6.5.4)|The requested resource could not be found.|None|
|
|404|[Not Found](https://tools.ietf.org/html/rfc7231#section-6.5.4)|The requested resource could not be found.|None|
|
||||||
|500|[Internal Server Error](https://tools.ietf.org/html/rfc7231#section-6.6.1)|Internal error.|None|
|
|500|[Internal Server Error](https://tools.ietf.org/html/rfc7231#section-6.6.1)|Internal error.|[ServerErrorResponse](#schemaservererrorresponse)|
|
||||||
|
|
||||||
<aside class="warning">
|
<aside class="warning">
|
||||||
To perform this operation, you must be authenticated by means of one of the following methods:
|
To perform this operation, you must be authenticated by means of one of the following methods:
|
||||||
|
@ -940,16 +983,24 @@ string
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
> 400 Response
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"message": "string"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
<h3 id="store-a-raw-blob-to-be-used-later-responses">Responses</h3>
|
<h3 id="store-a-raw-blob-to-be-used-later-responses">Responses</h3>
|
||||||
|
|
||||||
|Status|Meaning|Description|Schema|
|
|Status|Meaning|Description|Schema|
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|The operation was successful. The data was stored.|[FsBlobResponse](#schemafsblobresponse)|
|
|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|The operation was successful. The data was stored.|[FsBlobResponse](#schemafsblobresponse)|
|
||||||
|400|[Bad Request](https://tools.ietf.org/html/rfc7231#section-6.5.1)|Bad request. Please check error message and your parameters.|None|
|
|400|[Bad Request](https://tools.ietf.org/html/rfc7231#section-6.5.1)|Bad request. Please check error message and your parameters.|[ClientErrorResponse](#schemaclienterrorresponse)|
|
||||||
|401|[Unauthorized](https://tools.ietf.org/html/rfc7235#section-3.1)|Authorization failed. Please supply a `Bearer` token via the `Authorization` header.|None|
|
|401|[Unauthorized](https://tools.ietf.org/html/rfc7235#section-3.1)|Authorization failed. Please supply a `Bearer` token via the `Authorization` header.|None|
|
||||||
|403|[Forbidden](https://tools.ietf.org/html/rfc7231#section-6.5.3)|Authorization failed. Please supply a valid `Bearer` token via the `Authorization` header.|None|
|
|403|[Forbidden](https://tools.ietf.org/html/rfc7231#section-6.5.3)|Authorization failed. Please supply a valid `Bearer` token via the `Authorization` header.|None|
|
||||||
|404|[Not Found](https://tools.ietf.org/html/rfc7231#section-6.5.4)|The requested resource could not be found.|None|
|
|404|[Not Found](https://tools.ietf.org/html/rfc7231#section-6.5.4)|The requested resource could not be found.|None|
|
||||||
|500|[Internal Server Error](https://tools.ietf.org/html/rfc7231#section-6.6.1)|Internal error.|None|
|
|500|[Internal Server Error](https://tools.ietf.org/html/rfc7231#section-6.6.1)|Internal error.|[ServerErrorResponse](#schemaservererrorresponse)|
|
||||||
|
|
||||||
<aside class="warning">
|
<aside class="warning">
|
||||||
To perform this operation, you must be authenticated by means of one of the following methods:
|
To perform this operation, you must be authenticated by means of one of the following methods:
|
||||||
|
@ -1081,16 +1132,26 @@ Writes blob data to a file through an active shell session.
|
||||||
|---|---|---|---|---|
|
|---|---|---|---|---|
|
||||||
|body|body|[FsWriteRequest](#schemafswriterequest)|true|none|
|
|body|body|[FsWriteRequest](#schemafswriterequest)|true|none|
|
||||||
|
|
||||||
|
> Example responses
|
||||||
|
|
||||||
|
> 400 Response
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"message": "string"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
<h3 id="write-a-blob-to-a-remote-file-responses">Responses</h3>
|
<h3 id="write-a-blob-to-a-remote-file-responses">Responses</h3>
|
||||||
|
|
||||||
|Status|Meaning|Description|Schema|
|
|Status|Meaning|Description|Schema|
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|The operation was successful. The file was written.|None|
|
|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|The operation was successful. The file was written.|None|
|
||||||
|400|[Bad Request](https://tools.ietf.org/html/rfc7231#section-6.5.1)|Bad request. Please check error message and your parameters.|None|
|
|400|[Bad Request](https://tools.ietf.org/html/rfc7231#section-6.5.1)|Bad request. Please check error message and your parameters.|[ClientErrorResponse](#schemaclienterrorresponse)|
|
||||||
|401|[Unauthorized](https://tools.ietf.org/html/rfc7235#section-3.1)|Authorization failed. Please supply a `Bearer` token via the `Authorization` header.|None|
|
|401|[Unauthorized](https://tools.ietf.org/html/rfc7235#section-3.1)|Authorization failed. Please supply a `Bearer` token via the `Authorization` header.|None|
|
||||||
|403|[Forbidden](https://tools.ietf.org/html/rfc7231#section-6.5.3)|Authorization failed. Please supply a valid `Bearer` token via the `Authorization` header.|None|
|
|403|[Forbidden](https://tools.ietf.org/html/rfc7231#section-6.5.3)|Authorization failed. Please supply a valid `Bearer` token via the `Authorization` header.|None|
|
||||||
|404|[Not Found](https://tools.ietf.org/html/rfc7231#section-6.5.4)|The requested resource could not be found.|None|
|
|404|[Not Found](https://tools.ietf.org/html/rfc7231#section-6.5.4)|The requested resource could not be found.|None|
|
||||||
|500|[Internal Server Error](https://tools.ietf.org/html/rfc7231#section-6.6.1)|Internal error.|None|
|
|500|[Internal Server Error](https://tools.ietf.org/html/rfc7231#section-6.6.1)|Internal error.|[ServerErrorResponse](#schemaservererrorresponse)|
|
||||||
|
|
||||||
<aside class="warning">
|
<aside class="warning">
|
||||||
To perform this operation, you must be authenticated by means of one of the following methods:
|
To perform this operation, you must be authenticated by means of one of the following methods:
|
||||||
|
@ -1109,6 +1170,7 @@ const inputBody = '{
|
||||||
}';
|
}';
|
||||||
const headers = {
|
const headers = {
|
||||||
'Content-Type':'application/json',
|
'Content-Type':'application/json',
|
||||||
|
'Accept':'application/json',
|
||||||
'Authorization':'Bearer {access-token}'
|
'Authorization':'Bearer {access-token}'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1130,6 +1192,7 @@ fetch('http://localhost:21723/fs/write',
|
||||||
import requests
|
import requests
|
||||||
headers = {
|
headers = {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
|
'Accept': 'application/json',
|
||||||
'Authorization': 'Bearer {access-token}'
|
'Authorization': 'Bearer {access-token}'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1153,6 +1216,7 @@ var request = HttpRequest
|
||||||
.newBuilder()
|
.newBuilder()
|
||||||
.uri(uri)
|
.uri(uri)
|
||||||
.header("Content-Type", "application/json")
|
.header("Content-Type", "application/json")
|
||||||
|
.header("Accept", "application/json")
|
||||||
.header("Authorization", "Bearer {access-token}")
|
.header("Authorization", "Bearer {access-token}")
|
||||||
.POST(HttpRequest.BodyPublishers.ofString("""
|
.POST(HttpRequest.BodyPublishers.ofString("""
|
||||||
{
|
{
|
||||||
|
@ -1180,6 +1244,7 @@ func main() {
|
||||||
|
|
||||||
headers := map[string][]string{
|
headers := map[string][]string{
|
||||||
"Content-Type": []string{"application/json"},
|
"Content-Type": []string{"application/json"},
|
||||||
|
"Accept": []string{"application/json"},
|
||||||
"Authorization": []string{"Bearer {access-token}"},
|
"Authorization": []string{"Bearer {access-token}"},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1197,7 +1262,7 @@ func main() {
|
||||||
```shell
|
```shell
|
||||||
# You can also use wget
|
# You can also use wget
|
||||||
curl -X POST http://localhost:21723/fs/write \
|
curl -X POST http://localhost:21723/fs/write \
|
||||||
-H 'Content-Type: application/json' \ -H 'Authorization: Bearer {access-token}' \
|
-H 'Content-Type: application/json' \ -H 'Accept: application/json' \ -H 'Authorization: Bearer {access-token}' \
|
||||||
--data '
|
--data '
|
||||||
{
|
{
|
||||||
"connection": "f0ec68aa-63f5-405c-b178-9a4454556d6b",
|
"connection": "f0ec68aa-63f5-405c-b178-9a4454556d6b",
|
||||||
|
@ -1245,16 +1310,24 @@ This can be used to run more complex commands on remote systems.
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
> 400 Response
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"message": "string"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
<h3 id="create-a-shell-script-file-from-a-blob-responses">Responses</h3>
|
<h3 id="create-a-shell-script-file-from-a-blob-responses">Responses</h3>
|
||||||
|
|
||||||
|Status|Meaning|Description|Schema|
|
|Status|Meaning|Description|Schema|
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|The operation was successful. The script file was created.|[FsScriptResponse](#schemafsscriptresponse)|
|
|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|The operation was successful. The script file was created.|[FsScriptResponse](#schemafsscriptresponse)|
|
||||||
|400|[Bad Request](https://tools.ietf.org/html/rfc7231#section-6.5.1)|Bad request. Please check error message and your parameters.|None|
|
|400|[Bad Request](https://tools.ietf.org/html/rfc7231#section-6.5.1)|Bad request. Please check error message and your parameters.|[ClientErrorResponse](#schemaclienterrorresponse)|
|
||||||
|401|[Unauthorized](https://tools.ietf.org/html/rfc7235#section-3.1)|Authorization failed. Please supply a `Bearer` token via the `Authorization` header.|None|
|
|401|[Unauthorized](https://tools.ietf.org/html/rfc7235#section-3.1)|Authorization failed. Please supply a `Bearer` token via the `Authorization` header.|None|
|
||||||
|403|[Forbidden](https://tools.ietf.org/html/rfc7231#section-6.5.3)|Authorization failed. Please supply a valid `Bearer` token via the `Authorization` header.|None|
|
|403|[Forbidden](https://tools.ietf.org/html/rfc7231#section-6.5.3)|Authorization failed. Please supply a valid `Bearer` token via the `Authorization` header.|None|
|
||||||
|404|[Not Found](https://tools.ietf.org/html/rfc7231#section-6.5.4)|The requested resource could not be found.|None|
|
|404|[Not Found](https://tools.ietf.org/html/rfc7231#section-6.5.4)|The requested resource could not be found.|None|
|
||||||
|500|[Internal Server Error](https://tools.ietf.org/html/rfc7231#section-6.6.1)|Internal error.|None|
|
|500|[Internal Server Error](https://tools.ietf.org/html/rfc7231#section-6.6.1)|Internal error.|[ServerErrorResponse](#schemaservererrorresponse)|
|
||||||
|
|
||||||
<aside class="warning">
|
<aside class="warning">
|
||||||
To perform this operation, you must be authenticated by means of one of the following methods:
|
To perform this operation, you must be authenticated by means of one of the following methods:
|
||||||
|
@ -1783,3 +1856,58 @@ and
|
||||||
|*anonymous*|object|false|none|none|
|
|*anonymous*|object|false|none|none|
|
||||||
|» name|string|true|none|The name of the client.|
|
|» name|string|true|none|The name of the client.|
|
||||||
|
|
||||||
|
<h2 id="tocS_ClientErrorResponse">ClientErrorResponse</h2>
|
||||||
|
|
||||||
|
<a id="schemaclienterrorresponse"></a>
|
||||||
|
<a id="schema_ClientErrorResponse"></a>
|
||||||
|
<a id="tocSclienterrorresponse"></a>
|
||||||
|
<a id="tocsclienterrorresponse"></a>
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"message": "string"
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
Error returned in case of a client exception
|
||||||
|
|
||||||
|
<h3>Properties</h3>
|
||||||
|
|
||||||
|
|Name|Type|Required|Restrictions|Description|
|
||||||
|
|---|---|---|---|---|
|
||||||
|
|message|string|true|none|The error message|
|
||||||
|
|
||||||
|
<h2 id="tocS_ServerErrorResponse">ServerErrorResponse</h2>
|
||||||
|
|
||||||
|
<a id="schemaservererrorresponse"></a>
|
||||||
|
<a id="schema_ServerErrorResponse"></a>
|
||||||
|
<a id="tocSservererrorresponse"></a>
|
||||||
|
<a id="tocsservererrorresponse"></a>
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"error": {
|
||||||
|
"cause": {},
|
||||||
|
"stackTrace": [],
|
||||||
|
"suppressed": [],
|
||||||
|
"localizedMessage": "string",
|
||||||
|
"message": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
Error returned in case of a server exception with HTTP code 500
|
||||||
|
|
||||||
|
<h3>Properties</h3>
|
||||||
|
|
||||||
|
|Name|Type|Required|Restrictions|Description|
|
||||||
|
|---|---|---|---|---|
|
||||||
|
|error|object|true|none|The exception information|
|
||||||
|
|» cause|object|false|none|The exception cause|
|
||||||
|
|» stackTrace|array|false|none|The java stack trace information|
|
||||||
|
|» suppressed|array|false|none|Any suppressed exceptions|
|
||||||
|
|» localizedMessage|string|false|none|Not used|
|
||||||
|
|» message|string|true|none|The error message|
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ import io.xpipe.beacon.BeaconInterface;
|
||||||
import io.xpipe.core.util.SecretValue;
|
import io.xpipe.core.util.SecretValue;
|
||||||
|
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
|
import lombok.NonNull;
|
||||||
import lombok.Value;
|
import lombok.Value;
|
||||||
import lombok.extern.jackson.Jacksonized;
|
import lombok.extern.jackson.Jacksonized;
|
||||||
|
|
||||||
|
@ -31,6 +32,7 @@ public class AskpassExchange extends BeaconInterface<AskpassExchange.Request> {
|
||||||
@Builder
|
@Builder
|
||||||
@Value
|
@Value
|
||||||
public static class Response {
|
public static class Response {
|
||||||
|
@NonNull
|
||||||
SecretValue value;
|
SecretValue value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
package io.xpipe.beacon.api;
|
package io.xpipe.beacon.api;
|
||||||
|
|
||||||
import io.xpipe.beacon.BeaconInterface;
|
import io.xpipe.beacon.BeaconInterface;
|
||||||
|
import io.xpipe.core.process.OsType;
|
||||||
|
import io.xpipe.core.process.ShellDialect;
|
||||||
|
import io.xpipe.core.store.FilePath;
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
import lombok.Value;
|
import lombok.Value;
|
||||||
|
@ -27,5 +29,14 @@ public class ShellStartExchange extends BeaconInterface<ShellStartExchange.Reque
|
||||||
@Jacksonized
|
@Jacksonized
|
||||||
@Builder
|
@Builder
|
||||||
@Value
|
@Value
|
||||||
public static class Response {}
|
public static class Response {
|
||||||
|
@NonNull
|
||||||
|
ShellDialect shellDialect;
|
||||||
|
@NonNull
|
||||||
|
OsType osType;
|
||||||
|
@NonNull
|
||||||
|
String osName;
|
||||||
|
@NonNull
|
||||||
|
FilePath temp;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,10 @@ import java.util.function.Function;
|
||||||
|
|
||||||
public interface ShellControl extends ProcessControl {
|
public interface ShellControl extends ProcessControl {
|
||||||
|
|
||||||
|
void setNonInteractive();
|
||||||
|
|
||||||
|
boolean isInteractive();
|
||||||
|
|
||||||
ElevationHandler getElevationHandler();
|
ElevationHandler getElevationHandler();
|
||||||
|
|
||||||
void setElevationHandler(ElevationHandler ref);
|
void setElevationHandler(ElevationHandler ref);
|
||||||
|
|
45
openapi.yaml
45
openapi.yaml
|
@ -8,7 +8,6 @@ info:
|
||||||
<a download href="/openapi.yaml" style="font-size: 20px">OpenAPI .yaml specification</a>
|
<a download href="/openapi.yaml" style="font-size: 20px">OpenAPI .yaml specification</a>
|
||||||
|
|
||||||
The XPipe application will start up an HTTP server that can be used to send requests.
|
The XPipe application will start up an HTTP server that can be used to send requests.
|
||||||
You can change the port of it in the settings menu.
|
|
||||||
Note that this server is HTTP-only for now as it runs only on localhost. HTTPS requests are not accepted.
|
Note that this server is HTTP-only for now as it runs only on localhost. HTTPS requests are not accepted.
|
||||||
|
|
||||||
This allows you to programmatically manage remote systems.
|
This allows you to programmatically manage remote systems.
|
||||||
|
@ -544,11 +543,51 @@ components:
|
||||||
description: The name of the client.
|
description: The name of the client.
|
||||||
required:
|
required:
|
||||||
- name
|
- name
|
||||||
|
ClientErrorResponse:
|
||||||
|
description: Error returned in case of a client exception
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
message:
|
||||||
|
type: string
|
||||||
|
description: The error message
|
||||||
|
required:
|
||||||
|
- message
|
||||||
|
ServerErrorResponse:
|
||||||
|
description: Error returned in case of a server exception with HTTP code 500
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
error:
|
||||||
|
type: object
|
||||||
|
description: The exception information
|
||||||
|
properties:
|
||||||
|
cause:
|
||||||
|
type: object
|
||||||
|
description: The exception cause
|
||||||
|
stackTrace:
|
||||||
|
type: array
|
||||||
|
description: The java stack trace information
|
||||||
|
suppressed:
|
||||||
|
type: array
|
||||||
|
description: Any suppressed exceptions
|
||||||
|
localizedMessage:
|
||||||
|
type: string
|
||||||
|
description: Not used
|
||||||
|
message:
|
||||||
|
type: string
|
||||||
|
description: The error message
|
||||||
|
required:
|
||||||
|
- message
|
||||||
|
required:
|
||||||
|
- error
|
||||||
responses:
|
responses:
|
||||||
Success:
|
Success:
|
||||||
description: The action was successfully performed.
|
description: The action was successfully performed.
|
||||||
BadRequest:
|
BadRequest:
|
||||||
description: Bad request. Please check error message and your parameters.
|
description: Bad request. Please check error message and your parameters.
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/ClientErrorResponse'
|
||||||
Unauthorized:
|
Unauthorized:
|
||||||
description: Authorization failed. Please supply a `Bearer` token via
|
description: Authorization failed. Please supply a `Bearer` token via
|
||||||
the `Authorization` header.
|
the `Authorization` header.
|
||||||
|
@ -559,6 +598,10 @@ components:
|
||||||
description: The requested resource could not be found.
|
description: The requested resource could not be found.
|
||||||
InternalServerError:
|
InternalServerError:
|
||||||
description: Internal error.
|
description: Internal error.
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/ServerErrorResponse'
|
||||||
securitySchemes:
|
securitySchemes:
|
||||||
bearerAuth:
|
bearerAuth:
|
||||||
type: http
|
type: http
|
||||||
|
|
2
version
2
version
|
@ -1 +1 @@
|
||||||
10.0-9
|
10.0-10
|
||||||
|
|
Loading…
Reference in a new issue