better select secret screen
This commit is contained in:
parent
78b056a0b1
commit
3ebb1d1815
@ -50,11 +50,14 @@ bundle ui-dev
|
|||||||
if [ "WATCH" == "$1" ]; then
|
if [ "WATCH" == "$1" ]; then
|
||||||
|
|
||||||
echo watch mode
|
echo watch mode
|
||||||
|
echo Writting any file in the src directory will trigger a browser reload.
|
||||||
|
echo Be sure that the watcher server is running.
|
||||||
inotifywait -e close_write -r src -q -m | while read line; do
|
inotifywait -e close_write -r src -q -m | while read line; do
|
||||||
DATE=$(date)
|
echo $(date) $line
|
||||||
echo $DATE $line
|
|
||||||
build_js src/main.ts
|
build_js src/main.ts
|
||||||
bundle ui-dev
|
bundle ui-dev
|
||||||
./watch/send_reload.sh
|
#CONTENT=$(echo 'alert("hola")' | base64)
|
||||||
|
./watch/send.sh '{"type":"RELOAD"}'
|
||||||
|
#./watch/send.sh '{"type":"UPDATE","content":"'$CONTENT'"}'
|
||||||
done;
|
done;
|
||||||
fi
|
fi
|
||||||
|
@ -23,13 +23,13 @@
|
|||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div id="container" class="anastasis-container"></div>
|
<div id="container" class="anastasis-container"></div>
|
||||||
<script type="application/javascript">
|
<script id="code" type="application/javascript">
|
||||||
ANASTASIS_SCRIPT_CONTENT;
|
ANASTASIS_SCRIPT_CONTENT;
|
||||||
</script>
|
</script>
|
||||||
<script type="application/javascript">
|
<script type="application/javascript">
|
||||||
function setupLiveReload(port) {
|
function setupLiveReload() {
|
||||||
const socketPath = `ws://localhost:${port}/socket`;
|
const socketPath = `ws://localhost:8003/socket`;
|
||||||
|
console.log("connecting to ", socketPath)
|
||||||
const ws = new WebSocket(socketPath);
|
const ws = new WebSocket(socketPath);
|
||||||
ws.onmessage = (message) => {
|
ws.onmessage = (message) => {
|
||||||
const event = JSON.parse(message.data);
|
const event = JSON.parse(message.data);
|
||||||
@ -39,12 +39,27 @@
|
|||||||
if (event.type === "RELOAD") {
|
if (event.type === "RELOAD") {
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
}
|
}
|
||||||
|
if (event.type === "UPDATE") {
|
||||||
|
document.body.removeChild(document.getElementById("container"))
|
||||||
|
const d = document.createElement('div')
|
||||||
|
d.setAttribute('id',"container")
|
||||||
|
d.setAttribute('class',"anastasis-container");
|
||||||
|
document.body.appendChild(d)
|
||||||
|
const s = document.createElement('script')
|
||||||
|
s.setAttribute('id',"code")
|
||||||
|
s.setAttribute('type',"application/javascript");
|
||||||
|
s.textContent = atob(event.content)
|
||||||
|
document.body.appendChild(s)
|
||||||
|
}
|
||||||
};
|
};
|
||||||
ws.onerror = (error) => {
|
ws.onerror = (error) => {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
};
|
};
|
||||||
|
ws.onclose = (e) => {
|
||||||
|
setTimeout(setupLiveReload, 500)
|
||||||
|
};
|
||||||
}
|
}
|
||||||
setupLiveReload(8003);
|
setupLiveReload();
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -45,7 +45,6 @@ export function FileButton(props: Props): VNode {
|
|||||||
if (!f || f.length != 1) {
|
if (!f || f.length != 1) {
|
||||||
return props.onChange(undefined);
|
return props.onChange(undefined);
|
||||||
}
|
}
|
||||||
console.log(f);
|
|
||||||
if (f[0].size > MAX_IMAGE_UPLOAD_SIZE) {
|
if (f[0].size > MAX_IMAGE_UPLOAD_SIZE) {
|
||||||
setSizeError(true);
|
setSizeError(true);
|
||||||
return props.onChange(undefined);
|
return props.onChange(undefined);
|
||||||
|
@ -75,7 +75,6 @@ export function FileInput(props: FileInputProps): VNode {
|
|||||||
if (!f || f.length != 1) {
|
if (!f || f.length != 1) {
|
||||||
return props.onChange(undefined);
|
return props.onChange(undefined);
|
||||||
}
|
}
|
||||||
console.log(f);
|
|
||||||
if (f[0].size > MAX_IMAGE_UPLOAD_SIZE) {
|
if (f[0].size > MAX_IMAGE_UPLOAD_SIZE) {
|
||||||
setSizeError(true);
|
setSizeError(true);
|
||||||
return props.onChange(undefined);
|
return props.onChange(undefined);
|
||||||
|
@ -66,9 +66,7 @@ export function useAsync<T>(
|
|||||||
}, tooLong);
|
}, tooLong);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
console.log("calling async", args);
|
|
||||||
const result = await fn(...args);
|
const result = await fn(...args);
|
||||||
console.log("async back", result);
|
|
||||||
if (!isMounted()) {
|
if (!isMounted()) {
|
||||||
// Possibly calling fn(...) resulted in the component being unmounted.
|
// Possibly calling fn(...) resulted in the component being unmounted.
|
||||||
return;
|
return;
|
||||||
|
@ -177,7 +177,6 @@ function getStateFromStorage(): any {
|
|||||||
if (s === "undefined") {
|
if (s === "undefined") {
|
||||||
state = undefined;
|
state = undefined;
|
||||||
} else if (s) {
|
} else if (s) {
|
||||||
console.log("restoring state from", s);
|
|
||||||
state = JSON.parse(s);
|
state = JSON.parse(s);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -225,7 +224,6 @@ export function useAnastasisReducer(): AnastasisReducerApi {
|
|||||||
if (Object.keys(updates).length === 0) {
|
if (Object.keys(updates).length === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
console.log("got provider updates", updates);
|
|
||||||
const rs2 = reducerState;
|
const rs2 = reducerState;
|
||||||
if (rs2.reducer_type !== "backup" && rs2.reducer_type !== "recovery") {
|
if (rs2.reducer_type !== "backup" && rs2.reducer_type !== "recovery") {
|
||||||
return;
|
return;
|
||||||
@ -248,19 +246,15 @@ export function useAnastasisReducer(): AnastasisReducerApi {
|
|||||||
};
|
};
|
||||||
|
|
||||||
async function doTransition(action: string, args: any): Promise<void> {
|
async function doTransition(action: string, args: any): Promise<void> {
|
||||||
console.log("reducing with", action, args);
|
|
||||||
let s: ReducerState;
|
let s: ReducerState;
|
||||||
if (remoteReducer) {
|
if (remoteReducer) {
|
||||||
s = await reduceStateRemote(anastasisState.reducerState, action, args);
|
s = await reduceStateRemote(anastasisState.reducerState, action, args);
|
||||||
} else {
|
} else {
|
||||||
s = await reduceAction(anastasisState.reducerState!, action, args);
|
s = await reduceAction(anastasisState.reducerState!, action, args);
|
||||||
}
|
}
|
||||||
console.log("got response from reducer", s);
|
|
||||||
if (s.reducer_type === "error") {
|
if (s.reducer_type === "error") {
|
||||||
console.log("response is an error");
|
|
||||||
setAnastasisState({ ...anastasisState, currentError: s });
|
setAnastasisState({ ...anastasisState, currentError: s });
|
||||||
} else {
|
} else {
|
||||||
console.log("response is a new state");
|
|
||||||
setAnastasisState({
|
setAnastasisState({
|
||||||
...anastasisState,
|
...anastasisState,
|
||||||
currentError: undefined,
|
currentError: undefined,
|
||||||
@ -387,7 +381,6 @@ export function useAnastasisReducer(): AnastasisReducerApi {
|
|||||||
console.log("exception during reducer transaction", e);
|
console.log("exception during reducer transaction", e);
|
||||||
}
|
}
|
||||||
const s = txHandle.transactionState;
|
const s = txHandle.transactionState;
|
||||||
console.log("transaction finished, new state", s);
|
|
||||||
if (s.reducer_type === "error") {
|
if (s.reducer_type === "error") {
|
||||||
setAnastasisState({
|
setAnastasisState({
|
||||||
...anastasisState,
|
...anastasisState,
|
||||||
@ -413,7 +406,6 @@ class ReducerTxImpl implements ReducerTransactionHandle {
|
|||||||
} else {
|
} else {
|
||||||
s = await reduceAction(this.transactionState, action, args);
|
s = await reduceAction(this.transactionState, action, args);
|
||||||
}
|
}
|
||||||
console.log("making transition in transaction", action);
|
|
||||||
this.transactionState = s;
|
this.transactionState = s;
|
||||||
// Abort transaction as soon as we transition into an error state.
|
// Abort transaction as soon as we transition into an error state.
|
||||||
if (this.transactionState.reducer_type === "error") {
|
if (this.transactionState.reducer_type === "error") {
|
||||||
|
@ -13,7 +13,11 @@
|
|||||||
You should have received a copy of the GNU Affero General Public License along with
|
You should have received a copy of the GNU Affero General Public License along with
|
||||||
GNU Anastasis; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
GNU Anastasis; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||||
*/
|
*/
|
||||||
import { AuthenticationProviderStatusOk } from "@gnu-taler/anastasis-core";
|
import {
|
||||||
|
AuthenticationProviderStatus,
|
||||||
|
AuthenticationProviderStatusError,
|
||||||
|
AuthenticationProviderStatusOk,
|
||||||
|
} from "@gnu-taler/anastasis-core";
|
||||||
import { h, VNode } from "preact";
|
import { h, VNode } from "preact";
|
||||||
import { useEffect, useRef, useState } from "preact/hooks";
|
import { useEffect, useRef, useState } from "preact/hooks";
|
||||||
import { TextInput } from "../../components/fields/TextInput.js";
|
import { TextInput } from "../../components/fields/TextInput.js";
|
||||||
@ -38,7 +42,6 @@ async function testProvider(
|
|||||||
"This provider doesn't have authentication method. Check the provider URL",
|
"This provider doesn't have authentication method. Check the provider URL",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
console.log("expected", expectedMethodType);
|
|
||||||
if (!expectedMethodType) {
|
if (!expectedMethodType) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -68,8 +71,10 @@ export function AddingProviderScreen({ providerType, onCancel }: Props): VNode {
|
|||||||
const reducer = useAnastasisContext();
|
const reducer = useAnastasisContext();
|
||||||
|
|
||||||
const [providerURL, setProviderURL] = useState("");
|
const [providerURL, setProviderURL] = useState("");
|
||||||
|
|
||||||
const [error, setError] = useState<string | undefined>();
|
const [error, setError] = useState<string | undefined>();
|
||||||
const [testing, setTesting] = useState(false);
|
const [testing, setTesting] = useState(false);
|
||||||
|
|
||||||
const providerLabel = providerType
|
const providerLabel = providerType
|
||||||
? authMethods[providerType].label
|
? authMethods[providerType].label
|
||||||
: undefined;
|
: undefined;
|
||||||
@ -81,19 +86,32 @@ export function AddingProviderScreen({ providerType, onCancel }: Props): VNode {
|
|||||||
!reducer.currentReducerState.authentication_providers
|
!reducer.currentReducerState.authentication_providers
|
||||||
? {}
|
? {}
|
||||||
: reducer.currentReducerState.authentication_providers;
|
: reducer.currentReducerState.authentication_providers;
|
||||||
const authProviders = Object.keys(allAuthProviders).filter((provUrl) => {
|
|
||||||
const p = allAuthProviders[provUrl];
|
|
||||||
if (!providerLabel) {
|
|
||||||
return p && "currency" in p;
|
|
||||||
} else {
|
|
||||||
return (
|
|
||||||
p &&
|
|
||||||
"currency" in p &&
|
|
||||||
p.methods.findIndex((m) => m.type === providerType) !== -1
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
const authProvidersByStatus = Object.keys(allAuthProviders).reduce(
|
||||||
|
(prev, url) => {
|
||||||
|
const p = allAuthProviders[url];
|
||||||
|
if (
|
||||||
|
providerLabel &&
|
||||||
|
p.status === "ok" &&
|
||||||
|
p.methods.findIndex((m) => m.type === providerType) !== -1
|
||||||
|
) {
|
||||||
|
return prev;
|
||||||
|
}
|
||||||
|
const others = prev[p.status] ? prev[p.status] : [];
|
||||||
|
others.push({ ...p, url });
|
||||||
|
return {
|
||||||
|
...prev,
|
||||||
|
[p.status]: others,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
{} as Record<
|
||||||
|
AuthenticationProviderStatus["status"],
|
||||||
|
(AuthenticationProviderStatus & { url: string })[]
|
||||||
|
>,
|
||||||
|
);
|
||||||
|
const authProviders = authProvidersByStatus["ok"].map((p) => p.url);
|
||||||
|
|
||||||
|
console.log("rodos", allAuthProviders);
|
||||||
//FIXME: move this timeout logic into a hook
|
//FIXME: move this timeout logic into a hook
|
||||||
const timeout = useRef<number | undefined>(undefined);
|
const timeout = useRef<number | undefined>(undefined);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -211,6 +229,17 @@ export function AddingProviderScreen({ providerType, onCancel }: Props): VNode {
|
|||||||
<TableRow key={k} url={k} info={p} onDelete={deleteProvider} />
|
<TableRow key={k} url={k} info={p} onDelete={deleteProvider} />
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
{authProvidersByStatus["error"]?.map((k) => {
|
||||||
|
const p = k as AuthenticationProviderStatusError;
|
||||||
|
return (
|
||||||
|
<TableRowError
|
||||||
|
key={k}
|
||||||
|
url={k.url}
|
||||||
|
info={p}
|
||||||
|
onDelete={deleteProvider}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
</div>
|
</div>
|
||||||
</AnastasisClientFrame>
|
</AnastasisClientFrame>
|
||||||
);
|
);
|
||||||
@ -277,3 +306,62 @@ function TableRow({
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function TableRowError({
|
||||||
|
url,
|
||||||
|
info,
|
||||||
|
onDelete,
|
||||||
|
}: {
|
||||||
|
onDelete: (s: string) => void;
|
||||||
|
url: string;
|
||||||
|
info: AuthenticationProviderStatusError;
|
||||||
|
}): VNode {
|
||||||
|
const [status, setStatus] = useState("checking");
|
||||||
|
useEffect(function () {
|
||||||
|
testProvider(url.endsWith("/") ? url.substring(0, url.length - 1) : url)
|
||||||
|
.then(function () {
|
||||||
|
setStatus("responding");
|
||||||
|
})
|
||||||
|
.catch(function () {
|
||||||
|
setStatus("failed to contact");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
class="box"
|
||||||
|
style={{ display: "flex", justifyContent: "space-between" }}
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<div class="subtitle">{url}</div>
|
||||||
|
<dl>
|
||||||
|
<dt>
|
||||||
|
<b>Error</b>
|
||||||
|
</dt>
|
||||||
|
<dd>{info.hint}</dd>
|
||||||
|
<dt>
|
||||||
|
<b>Code</b>
|
||||||
|
</dt>
|
||||||
|
<dd>{info.code}</dd>
|
||||||
|
<dt>
|
||||||
|
<b>Status</b>
|
||||||
|
</dt>
|
||||||
|
<dd>{status}</dd>
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="block"
|
||||||
|
style={{
|
||||||
|
marginTop: "auto",
|
||||||
|
marginBottom: "auto",
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
flexDirection: "column",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<button class="button is-danger" onClick={() => onDelete(url)}>
|
||||||
|
Remove
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@ -91,20 +91,64 @@ export function SecretSelectionScreen(): VNode {
|
|||||||
title="Recovery: Select secret"
|
title="Recovery: Select secret"
|
||||||
hideNext="Please select version to recover"
|
hideNext="Please select version to recover"
|
||||||
>
|
>
|
||||||
<p>Found versions:</p>
|
<div class="columns">
|
||||||
{policies.map((version, i) => (
|
<div class="column">
|
||||||
<div key={i}>
|
<p class="block">Found versions:</p>
|
||||||
{version.policy_hash} / {version.secret_name}
|
{policies.map((version, i) => (
|
||||||
<button
|
<div key={i} class="box">
|
||||||
onClick={async () => {
|
<div
|
||||||
await reducer.transition("select_version", version);
|
class="block"
|
||||||
}}
|
style={{ display: "flex", justifyContent: "space-between" }}
|
||||||
>
|
>
|
||||||
Recover
|
<div
|
||||||
</button>
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div style={{ display: "flex", alignItems: "center" }}>
|
||||||
|
<b>Name:</b> <span>{version.secret_name}</span>
|
||||||
|
</div>
|
||||||
|
<div style={{ display: "flex", alignItems: "center" }}>
|
||||||
|
<b>Id:</b>
|
||||||
|
<span
|
||||||
|
class="icon has-tooltip-top"
|
||||||
|
data-tooltip={version.policy_hash
|
||||||
|
.match(/(.{22})/g)
|
||||||
|
?.join("\n")}
|
||||||
|
>
|
||||||
|
<i class="mdi mdi-information" />
|
||||||
|
</span>
|
||||||
|
<span>{version.policy_hash.substring(0, 22)}...</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<AsyncButton
|
||||||
|
class="button"
|
||||||
|
onClick={() =>
|
||||||
|
reducer.transition("select_version", version)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Recover
|
||||||
|
</AsyncButton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
</div>
|
</div>
|
||||||
))}
|
<div class="column">
|
||||||
<button>Load older versions</button>
|
<p>
|
||||||
|
Secret found, you can select another version or continue to the
|
||||||
|
challenges solving
|
||||||
|
</p>
|
||||||
|
<p class="block">
|
||||||
|
<a onClick={() => setManageProvider(true)}>
|
||||||
|
Manage recovery providers
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</AnastasisClientFrame>
|
</AnastasisClientFrame>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -85,7 +85,6 @@ export function AuthMethodTotpSolve(props: AuthMethodSolveProps): VNode {
|
|||||||
const feedback = challengeFeedback[selectedUuid];
|
const feedback = challengeFeedback[selectedUuid];
|
||||||
|
|
||||||
async function onNext(): Promise<void> {
|
async function onNext(): Promise<void> {
|
||||||
console.log(`sending TOTP code '${answerCode}'`);
|
|
||||||
return reducer?.transition("solve_challenge", {
|
return reducer?.transition("solve_challenge", {
|
||||||
answer: answerCode,
|
answer: answerCode,
|
||||||
});
|
});
|
||||||
|
@ -146,7 +146,7 @@ export function AnastasisClientFrame(props: AnastasisClientFrameProps): VNode {
|
|||||||
const handleKeyPress = (
|
const handleKeyPress = (
|
||||||
e: h.JSX.TargetedKeyboardEvent<HTMLDivElement>,
|
e: h.JSX.TargetedKeyboardEvent<HTMLDivElement>,
|
||||||
): void => {
|
): void => {
|
||||||
console.log("Got key press", e.key);
|
// console.log("Got key press", e.key);
|
||||||
// FIXME: By default, "next" action should be executed here
|
// FIXME: By default, "next" action should be executed here
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -227,7 +227,6 @@ function AnastasisClientImpl(): VNode {
|
|||||||
if (!state) {
|
if (!state) {
|
||||||
return <StartScreen />;
|
return <StartScreen />;
|
||||||
}
|
}
|
||||||
console.log("state", reducer.currentReducerState);
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
(state.reducer_type === "backup" &&
|
(state.reducer_type === "backup" &&
|
||||||
|
@ -381,4 +381,7 @@ function setupLiveReload(port: number, onReload: () => void): void {
|
|||||||
ws.onerror = (error) => {
|
ws.onerror = (error) => {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
};
|
};
|
||||||
|
ws.onclose = (e) => {
|
||||||
|
console.log("disconnected", e);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
@ -14,4 +14,5 @@ done
|
|||||||
|
|
||||||
cat watch/web_socket_server.reply | sed 's/$'"/`echo \\\r`/" | envsubst '$WS_ACCEPT'
|
cat watch/web_socket_server.reply | sed 's/$'"/`echo \\\r`/" | envsubst '$WS_ACCEPT'
|
||||||
|
|
||||||
socat UNIX-RECV:./send_signal STDOUT
|
tail -n 0 -F /tmp/send_signal 2> /dev/null
|
||||||
|
|
||||||
|
12
packages/anastasis-webui/watch/send.sh
Executable file
12
packages/anastasis-webui/watch/send.sh
Executable file
@ -0,0 +1,12 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
#https://datatracker.ietf.org/doc/html/rfc6455#page-65
|
||||||
|
|
||||||
|
COMMAND=$1
|
||||||
|
LEN=$(printf '%x\n' ${#COMMAND})
|
||||||
|
|
||||||
|
#text command
|
||||||
|
OPCODE=81
|
||||||
|
|
||||||
|
cat <(echo -n $OPCODE$LEN | xxd -r -p) <(echo -n $COMMAND) >> /tmp/send_signal
|
||||||
|
|
14
packages/anastasis-webui/watch/send2.sh
Executable file
14
packages/anastasis-webui/watch/send2.sh
Executable file
@ -0,0 +1,14 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
#https://datatracker.ietf.org/doc/html/rfc6455#page-65
|
||||||
|
|
||||||
|
CONTENT=$( cat $1 | base64 -w 0 )
|
||||||
|
COMMAND='{"type":"UPDATE","'$CONTENT'"}'
|
||||||
|
LEN=$(printf '%0*x\n' 4 ${#COMMAND})
|
||||||
|
echo $LEN
|
||||||
|
LEN=00000138
|
||||||
|
#text command
|
||||||
|
OPCODE=81
|
||||||
|
|
||||||
|
cat <(echo -n $OPCODE$LEN | xxd -r -p) <(echo -n $COMMAND) >> /tmp/send_signal
|
||||||
|
|
@ -1,7 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
COMMAND='{"type":"RELOAD"}'
|
|
||||||
LEN=$(printf '%x\n' ${#COMMAND})
|
|
||||||
OPCODE=81
|
|
||||||
cat <(echo -n $OPCODE$LEN | xxd -r -p) <(echo -n $COMMAND) | socat - UNIX-SEND:./send_signal
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
socat TCP-LISTEN:8003,fork EXEC:"./watch/reply.sh"
|
socat TCP-LISTEN:8003,fork,reuseaddr,keepalive EXEC:"./watch/reply.sh"
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user