better select secret screen
This commit is contained in:
parent
78b056a0b1
commit
3ebb1d1815
@ -50,11 +50,14 @@ bundle ui-dev
|
||||
if [ "WATCH" == "$1" ]; then
|
||||
|
||||
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
|
||||
DATE=$(date)
|
||||
echo $DATE $line
|
||||
echo $(date) $line
|
||||
build_js src/main.ts
|
||||
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;
|
||||
fi
|
||||
|
@ -23,13 +23,13 @@
|
||||
|
||||
<body>
|
||||
<div id="container" class="anastasis-container"></div>
|
||||
<script type="application/javascript">
|
||||
<script id="code" type="application/javascript">
|
||||
ANASTASIS_SCRIPT_CONTENT;
|
||||
</script>
|
||||
<script type="application/javascript">
|
||||
function setupLiveReload(port) {
|
||||
const socketPath = `ws://localhost:${port}/socket`;
|
||||
|
||||
function setupLiveReload() {
|
||||
const socketPath = `ws://localhost:8003/socket`;
|
||||
console.log("connecting to ", socketPath)
|
||||
const ws = new WebSocket(socketPath);
|
||||
ws.onmessage = (message) => {
|
||||
const event = JSON.parse(message.data);
|
||||
@ -39,12 +39,27 @@
|
||||
if (event.type === "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) => {
|
||||
console.error(error);
|
||||
};
|
||||
ws.onclose = (e) => {
|
||||
setTimeout(setupLiveReload, 500)
|
||||
};
|
||||
}
|
||||
setupLiveReload(8003);
|
||||
setupLiveReload();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -45,7 +45,6 @@ export function FileButton(props: Props): VNode {
|
||||
if (!f || f.length != 1) {
|
||||
return props.onChange(undefined);
|
||||
}
|
||||
console.log(f);
|
||||
if (f[0].size > MAX_IMAGE_UPLOAD_SIZE) {
|
||||
setSizeError(true);
|
||||
return props.onChange(undefined);
|
||||
|
@ -75,7 +75,6 @@ export function FileInput(props: FileInputProps): VNode {
|
||||
if (!f || f.length != 1) {
|
||||
return props.onChange(undefined);
|
||||
}
|
||||
console.log(f);
|
||||
if (f[0].size > MAX_IMAGE_UPLOAD_SIZE) {
|
||||
setSizeError(true);
|
||||
return props.onChange(undefined);
|
||||
|
@ -66,9 +66,7 @@ export function useAsync<T>(
|
||||
}, tooLong);
|
||||
|
||||
try {
|
||||
console.log("calling async", args);
|
||||
const result = await fn(...args);
|
||||
console.log("async back", result);
|
||||
if (!isMounted()) {
|
||||
// Possibly calling fn(...) resulted in the component being unmounted.
|
||||
return;
|
||||
|
@ -177,7 +177,6 @@ function getStateFromStorage(): any {
|
||||
if (s === "undefined") {
|
||||
state = undefined;
|
||||
} else if (s) {
|
||||
console.log("restoring state from", s);
|
||||
state = JSON.parse(s);
|
||||
}
|
||||
} catch (e) {
|
||||
@ -225,7 +224,6 @@ export function useAnastasisReducer(): AnastasisReducerApi {
|
||||
if (Object.keys(updates).length === 0) {
|
||||
return;
|
||||
}
|
||||
console.log("got provider updates", updates);
|
||||
const rs2 = reducerState;
|
||||
if (rs2.reducer_type !== "backup" && rs2.reducer_type !== "recovery") {
|
||||
return;
|
||||
@ -248,19 +246,15 @@ export function useAnastasisReducer(): AnastasisReducerApi {
|
||||
};
|
||||
|
||||
async function doTransition(action: string, args: any): Promise<void> {
|
||||
console.log("reducing with", action, args);
|
||||
let s: ReducerState;
|
||||
if (remoteReducer) {
|
||||
s = await reduceStateRemote(anastasisState.reducerState, action, args);
|
||||
} else {
|
||||
s = await reduceAction(anastasisState.reducerState!, action, args);
|
||||
}
|
||||
console.log("got response from reducer", s);
|
||||
if (s.reducer_type === "error") {
|
||||
console.log("response is an error");
|
||||
setAnastasisState({ ...anastasisState, currentError: s });
|
||||
} else {
|
||||
console.log("response is a new state");
|
||||
setAnastasisState({
|
||||
...anastasisState,
|
||||
currentError: undefined,
|
||||
@ -387,7 +381,6 @@ export function useAnastasisReducer(): AnastasisReducerApi {
|
||||
console.log("exception during reducer transaction", e);
|
||||
}
|
||||
const s = txHandle.transactionState;
|
||||
console.log("transaction finished, new state", s);
|
||||
if (s.reducer_type === "error") {
|
||||
setAnastasisState({
|
||||
...anastasisState,
|
||||
@ -413,7 +406,6 @@ class ReducerTxImpl implements ReducerTransactionHandle {
|
||||
} else {
|
||||
s = await reduceAction(this.transactionState, action, args);
|
||||
}
|
||||
console.log("making transition in transaction", action);
|
||||
this.transactionState = s;
|
||||
// Abort transaction as soon as we transition into an error state.
|
||||
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
|
||||
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 { useEffect, useRef, useState } from "preact/hooks";
|
||||
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",
|
||||
);
|
||||
}
|
||||
console.log("expected", expectedMethodType);
|
||||
if (!expectedMethodType) {
|
||||
return;
|
||||
}
|
||||
@ -68,8 +71,10 @@ export function AddingProviderScreen({ providerType, onCancel }: Props): VNode {
|
||||
const reducer = useAnastasisContext();
|
||||
|
||||
const [providerURL, setProviderURL] = useState("");
|
||||
|
||||
const [error, setError] = useState<string | undefined>();
|
||||
const [testing, setTesting] = useState(false);
|
||||
|
||||
const providerLabel = providerType
|
||||
? authMethods[providerType].label
|
||||
: undefined;
|
||||
@ -81,19 +86,32 @@ export function AddingProviderScreen({ providerType, onCancel }: Props): VNode {
|
||||
!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
|
||||
const timeout = useRef<number | undefined>(undefined);
|
||||
useEffect(() => {
|
||||
@ -211,6 +229,17 @@ export function AddingProviderScreen({ providerType, onCancel }: Props): VNode {
|
||||
<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>
|
||||
</AnastasisClientFrame>
|
||||
);
|
||||
@ -277,3 +306,62 @@ function TableRow({
|
||||
</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"
|
||||
hideNext="Please select version to recover"
|
||||
>
|
||||
<p>Found versions:</p>
|
||||
<div class="columns">
|
||||
<div class="column">
|
||||
<p class="block">Found versions:</p>
|
||||
{policies.map((version, i) => (
|
||||
<div key={i}>
|
||||
{version.policy_hash} / {version.secret_name}
|
||||
<button
|
||||
onClick={async () => {
|
||||
await reducer.transition("select_version", version);
|
||||
<div key={i} class="box">
|
||||
<div
|
||||
class="block"
|
||||
style={{ display: "flex", justifyContent: "space-between" }}
|
||||
>
|
||||
<div
|
||||
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
|
||||
</button>
|
||||
</AsyncButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
<button>Load older versions</button>
|
||||
</div>
|
||||
<div class="column">
|
||||
<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>
|
||||
);
|
||||
}
|
||||
|
@ -85,7 +85,6 @@ export function AuthMethodTotpSolve(props: AuthMethodSolveProps): VNode {
|
||||
const feedback = challengeFeedback[selectedUuid];
|
||||
|
||||
async function onNext(): Promise<void> {
|
||||
console.log(`sending TOTP code '${answerCode}'`);
|
||||
return reducer?.transition("solve_challenge", {
|
||||
answer: answerCode,
|
||||
});
|
||||
|
@ -146,7 +146,7 @@ export function AnastasisClientFrame(props: AnastasisClientFrameProps): VNode {
|
||||
const handleKeyPress = (
|
||||
e: h.JSX.TargetedKeyboardEvent<HTMLDivElement>,
|
||||
): void => {
|
||||
console.log("Got key press", e.key);
|
||||
// console.log("Got key press", e.key);
|
||||
// FIXME: By default, "next" action should be executed here
|
||||
};
|
||||
|
||||
@ -227,7 +227,6 @@ function AnastasisClientImpl(): VNode {
|
||||
if (!state) {
|
||||
return <StartScreen />;
|
||||
}
|
||||
console.log("state", reducer.currentReducerState);
|
||||
|
||||
if (
|
||||
(state.reducer_type === "backup" &&
|
||||
|
@ -381,4 +381,7 @@ function setupLiveReload(port: number, onReload: () => void): void {
|
||||
ws.onerror = (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'
|
||||
|
||||
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
|
||||
|
||||
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