This commit is contained in:
Sebastian 2022-08-26 12:59:00 -03:00
parent eef2d47020
commit cf894f1dd3
No known key found for this signature in database
GPG Key ID: BE4FF68352439FC1
18 changed files with 530 additions and 337 deletions

View File

@ -40,17 +40,20 @@ set -e
echo compile
build_css &
build_js src/main.ts &
build_js src/stories.tsx &
build_js src/main.test.ts &
for file in $(find src/ -name test.ts); do build_js $file; done &
wait -n
wait -n
wait -n
wait -n
wait -n
pnpm run --silent test -- -R dot
echo html
build_html ui
build_html ui-dev
build_html stories
if [ "WATCH" == "$1" ]; then
@ -62,6 +65,8 @@ if [ "WATCH" == "$1" ]; then
echo $(date) $line
build_js src/main.ts
build_html ui-dev
build_js src/stories.tsx
build_html stories
./watch/send.sh '{"type":"RELOAD"}'
done;
fi

View File

@ -28,11 +28,8 @@ interface Props {
mobile?: boolean;
}
// @ts-ignore
const maybeEnv = process?.env || {};
const VERSION: string = maybeEnv.__VERSION__ || "dev";
const GIT_HASH: string | undefined = maybeEnv.__GIT_HASH__;
const VERSION = typeof __VERSION__ !== "undefined" ? __VERSION__ : "dev";
const GIT_HASH = typeof __GIT_HASH__ !== "undefined" ? __GIT_HASH__ : undefined;
const VERSION_WITH_HASH = GIT_HASH ? `${VERSION}-${GIT_HASH}` : VERSION;
export function Sidebar({ mobile }: Props): VNode {

View File

@ -180,7 +180,7 @@ function getStateFromStorage(): any {
state = JSON.parse(s);
}
} catch (e) {
console.log(e);
console.log("ERROR: getStateFromStorage ", e);
}
return state ?? undefined;
}
@ -203,7 +203,7 @@ export function useAnastasisReducer(): AnastasisReducerApi {
JSON.stringify(newState.reducerState),
);
} catch (e) {
console.log(e);
console.log("ERROR setAnastasisState", e);
}
setAnastasisStateInternal(newState);
@ -239,7 +239,7 @@ export function useAnastasisReducer(): AnastasisReducerApi {
},
});
};
doUpdate().catch((e) => console.log(e));
doUpdate().catch((e) => console.log("ERROR doUpdate", e));
};
tryUpdateProviders();

View File

@ -16,6 +16,7 @@
import { AuthenticationProviderStatus } from "@gnu-taler/anastasis-core";
import InvalidState from "../../../components/InvalidState.js";
import NoReducer from "../../../components/NoReducer.js";
import { Notification } from "../../../components/Notifications.js";
import { compose, StateViewMap } from "../../../utils/index.js";
import useComponentState from "./state.js";
import { WithoutProviderType, WithProviderType } from "./views.js";
@ -44,6 +45,7 @@ interface CommonProps {
setProviderURL: (url: string) => Promise<void>;
providerURL: string;
errors: string | undefined;
notifications: Notification[];
}
export interface WithType extends CommonProps {
@ -90,7 +92,7 @@ export async function testProvider(
}
return;
} catch (e) {
console.log("error", e);
console.log("ERROR testProvider", e);
const error =
e instanceof Error
? Error(

View File

@ -14,6 +14,7 @@
GNU Anastasis; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
import { useEffect, useRef, useState } from "preact/hooks";
import { Notification } from "../../../components/Notifications.js";
import { useAnastasisContext } from "../../../context/anastasis.js";
import { authMethods, KnownAuthMethods } from "../authMethod/index.jsx";
import { AuthProvByStatusMap, State, testProvider } from "./index.js";
@ -21,9 +22,10 @@ import { AuthProvByStatusMap, State, testProvider } from "./index.js";
interface Props {
providerType?: KnownAuthMethods;
onCancel: () => Promise<void>;
notifications?: Notification[];
}
export default function useComponentState({ providerType, onCancel }: Props): State {
export default function useComponentState({ providerType, onCancel, notifications = [] }: Props): State {
const reducer = useAnastasisContext();
const [providerURL, setProviderURL] = useState("");
@ -128,6 +130,7 @@ export default function useComponentState({ providerType, onCancel }: Props): St
setProviderURL: async (s: string) => setProviderURL(s),
errors,
error,
notifications
}
if (!providerLabel) {

View File

@ -53,6 +53,7 @@ export const NewProvider = createExampleWithoutAnastasis(WithoutProviderType, {
disabled: [],
error: [],
},
notifications: [],
});
export const NewProviderWithoutProviderList = createExampleWithoutAnastasis(
@ -64,6 +65,7 @@ export const NewProviderWithoutProviderList = createExampleWithoutAnastasis(
disabled: [],
error: [],
},
notifications: [],
},
);
@ -75,6 +77,7 @@ export const NewSmsProvider = createExampleWithoutAnastasis(WithProviderType, {
error: [],
},
providerLabel: "sms",
notifications: [],
});
export const NewIBANProvider = createExampleWithoutAnastasis(WithProviderType, {
@ -85,4 +88,5 @@ export const NewIBANProvider = createExampleWithoutAnastasis(WithProviderType, {
error: [],
},
providerLabel: "IBAN",
notifications: [],
});

View File

@ -20,6 +20,7 @@ import {
import { h, VNode } from "preact";
import { useEffect, useState } from "preact/hooks";
import { TextInput } from "../../../components/fields/TextInput.js";
import { Notifications } from "../../../components/Notifications.js";
import { AnastasisClientFrame } from "../index.js";
import { testProvider, WithoutType, WithType } from "./index.js";
@ -31,6 +32,7 @@ export function WithProviderType(props: WithType): VNode {
hideNext={props.errors}
>
<div>
<Notifications notifications={props.notifications} />
<p>Add a provider url for a {props.providerLabel} service</p>
<div class="container">
<TextInput
@ -108,10 +110,11 @@ export function WithoutProviderType(props: WithoutType): VNode {
return (
<AnastasisClientFrame
hideNav
title="Backup: Manage providers2"
title="Backup: Manage providers"
hideNext={props.errors}
>
<div>
<Notifications notifications={props.notifications} />
<p>Add a provider url</p>
<div class="container">
<TextInput

View File

@ -174,85 +174,88 @@ export const OnePolicyWithAllTheChallengesInDifferentState = createExample(
{ uuid: "uuid-7" },
{ uuid: "uuid-8" },
{ uuid: "uuid-9" },
{ uuid: "uuid-10" },
],
],
challenges: [
{
instructions: 'in state "solved"',
instructions: 'this challenge is in state "solved"',
type: "question",
uuid: "uuid-1",
},
{
instructions: 'in state "message"',
instructions: 'this challenge is in state "code-in-file"',
type: "question",
uuid: "uuid-2",
},
{
instructions: 'in state "auth iban"',
instructions: 'this challenge is in state "code-sent"',
type: "question",
uuid: "uuid-3",
},
{
instructions: 'in state "payment "',
instructions: 'this challenge is in state "server-failure "',
type: "question",
uuid: "uuid-4",
},
{
instructions: 'in state "rate limit"',
instructions: 'this challenge is in state "truth-unknown"',
type: "question",
uuid: "uuid-5",
},
{
instructions: 'in state "redirect"',
instructions: 'this challenge is in state "taler-payment"',
type: "question",
uuid: "uuid-6",
},
{
instructions: 'in state "server failure"',
instructions: 'this challenge is in state "unsupported"',
type: "question",
uuid: "uuid-7",
},
{
instructions: 'in state "truth unknown"',
instructions: 'this challenge is in state "rate-limit-exceeded"',
type: "question",
uuid: "uuid-8",
},
{
instructions: 'in state "unsupported"',
instructions: 'this challenge is in state "iban-instructions"',
type: "question",
uuid: "uuid-9",
},
{
instructions: 'this challenge is in state "incorrect-answer"',
type: "question",
uuid: "uuid-10",
},
],
},
challenge_feedback: {
"uuid-1": { state: ChallengeFeedbackStatus.Solved.toString() },
"uuid-3": {
"uuid-2": { state: ChallengeFeedbackStatus.CodeInFile.toString() },
"uuid-3": { state: ChallengeFeedbackStatus.CodeSent.toString() },
"uuid-4": {
state: ChallengeFeedbackStatus.ServerFailure.toString(),
http_status: 500,
error_response: "some error message or error object",
},
"uuid-5": { state: ChallengeFeedbackStatus.TruthUnknown.toString() },
"uuid-6": {
state: ChallengeFeedbackStatus.TalerPayment.toString(),
taler_pay_uri: "taler://pay/...",
provider: "https://localhost:8080/",
payment_secret: "3P4561HAMHRRYEYD6CM6J7TS5VTD5SR2K2EXJDZEFSX92XKHR4KG",
},
"uuid-7": { state: ChallengeFeedbackStatus.Unsupported.toString() },
"uuid-8": { state: ChallengeFeedbackStatus.RateLimitExceeded.toString() },
"uuid-9": {
state: ChallengeFeedbackStatus.IbanInstructions.toString(),
challenge_amount: "EUR:1",
target_iban: "DE12345789000",
target_business_name: "Data Loss Incorporated",
wire_transfer_subject: "Anastasis 987654321",
},
"uuid-4": {
state: ChallengeFeedbackStatus.TalerPayment.toString(),
taler_pay_uri: "taler://pay/...",
provider: "https://localhost:8080/",
payment_secret: "3P4561HAMHRRYEYD6CM6J7TS5VTD5SR2K2EXJDZEFSX92XKHR4KG",
},
"uuid-5": {
state: ChallengeFeedbackStatus.RateLimitExceeded.toString(),
// "error_code": 8121
},
"uuid-7": {
state: ChallengeFeedbackStatus.ServerFailure.toString(),
http_status: 500,
error_response: "some error message or error object",
},
"uuid-8": {
state: ChallengeFeedbackStatus.TruthUnknown.toString(),
// "error_code": 8108
},
"uuid-9": { state: ChallengeFeedbackStatus.Unsupported.toString() },
"uuid-10": { state: ChallengeFeedbackStatus.IncorrectAnswer.toString() },
},
} as ReducerState,
);

View File

@ -17,22 +17,25 @@ import {
ChallengeFeedback,
ChallengeFeedbackStatus,
} from "@gnu-taler/anastasis-core";
import { h, VNode } from "preact";
import { Fragment, h, VNode } from "preact";
import { AsyncButton } from "../../components/AsyncButton.js";
import { useAnastasisContext } from "../../context/anastasis.js";
import { authMethods, KnownAuthMethods } from "./authMethod/index.js";
import { AnastasisClientFrame } from "./index.js";
function OverviewFeedbackDisplay(props: { feedback?: ChallengeFeedback }) {
function OverviewFeedbackDisplay(props: {
feedback?: ChallengeFeedback;
}): VNode {
const { feedback } = props;
if (!feedback) {
return null;
return <Fragment />;
}
switch (feedback.state) {
case ChallengeFeedbackStatus.Solved:
return <div />;
case ChallengeFeedbackStatus.IbanInstructions:
return null;
return <div class="block has-text-info">Payment required.</div>;
case ChallengeFeedbackStatus.ServerFailure:
return <div class="block has-text-danger">Server error.</div>;
case ChallengeFeedbackStatus.RateLimitExceeded:
@ -51,12 +54,20 @@ function OverviewFeedbackDisplay(props: { feedback?: ChallengeFeedback }) {
case ChallengeFeedbackStatus.TruthUnknown:
return (
<div class="block has-text-danger">
Provider doesn&apos;t recognize the challenge of the policy. Contact
the provider for further information.
Provider doesn&apos;t recognize the type of challenge. Use another
version or contact the provider.
</div>
);
default:
return <div />;
case ChallengeFeedbackStatus.IncorrectAnswer:
return (
<div class="block has-text-danger">The answer was not correct.</div>
);
case ChallengeFeedbackStatus.CodeInFile:
return <div class="block has-text-info">code in file</div>;
case ChallengeFeedbackStatus.CodeSent:
return <div class="block has-text-info">Code sent</div>;
case ChallengeFeedbackStatus.TalerPayment:
return <div class="block has-text-info">Payment required</div>;
}
}

View File

@ -21,29 +21,57 @@
import { ReducerState } from "@gnu-taler/anastasis-core";
import { createExample, reducerStatesExample } from "../../utils/index.js";
import { SecretSelectionScreen as TestedComponent } from "./SecretSelectionScreen.js";
import {
SecretSelectionScreen,
SecretSelectionScreenFound,
} from "./SecretSelectionScreen.js";
export default {
component: TestedComponent,
component: SecretSelectionScreen,
args: {
order: 4,
},
argTypes: {
onUpdate: { action: "onUpdate" },
onBack: { action: "onBack" },
},
};
export const Example = createExample(TestedComponent, {
...reducerStatesExample.secretSelection,
recovery_document: {
provider_url: "https://kudos.demo.anastasis.lu/",
secret_name: "secretName",
version: 1,
export const Example = createExample(
SecretSelectionScreenFound,
{
...reducerStatesExample.secretSelection,
recovery_document: {
provider_url: "https://kudos.demo.anastasis.lu/",
secret_name: "secretName",
version: 1,
},
} as ReducerState,
{
policies: [
{
secret_name: "The secret name 1",
attribute_mask: 1,
policy_hash: "abcdefghijklmnopqrstuvwxyz",
providers: [
{
url: "http://someurl",
version: 1,
},
],
},
{
secret_name: "The secret name 2",
attribute_mask: 1,
policy_hash: "abcdefghijklmnopqrstuvwxyz",
providers: [
{
url: "http://someurl",
version: 1,
},
],
},
],
},
} as ReducerState);
);
export const NoRecoveryDocumentFound = createExample(TestedComponent, {
export const NoRecoveryDocumentFound = createExample(SecretSelectionScreen, {
...reducerStatesExample.secretSelection,
recovery_document: undefined,
} as ReducerState);

View File

@ -14,6 +14,7 @@
GNU Anastasis; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
import {
AggregatedPolicyMetaInfo,
AuthenticationProviderStatus,
AuthenticationProviderStatusOk,
} from "@gnu-taler/anastasis-core";
@ -25,20 +26,16 @@ import { useAnastasisContext } from "../../context/anastasis.js";
import AddingProviderScreen from "./AddingProviderScreen/index.js";
import { AnastasisClientFrame } from "./index.js";
export function SecretSelectionScreen(): VNode {
const [selectingVersion, setSelectingVersion] = useState<boolean>(false);
export function SecretSelectionScreenFound({
policies,
onManageProvider,
onNext,
}: {
policies: AggregatedPolicyMetaInfo[];
onManageProvider: () => void;
onNext: (version: AggregatedPolicyMetaInfo) => void;
}): VNode {
const reducer = useAnastasisContext();
const [manageProvider, setManageProvider] = useState(false);
useEffect(() => {
async function f() {
if (reducer) {
await reducer.discoverStart();
}
}
f().catch((e) => console.log(e));
}, []);
if (!reducer) {
return <div>no reducer in context</div>;
}
@ -49,45 +46,6 @@ export function SecretSelectionScreen(): VNode {
) {
return <div>invalid state</div>;
}
const provs = reducer.currentReducerState.authentication_providers ?? {};
const recoveryDocument = reducer.currentReducerState.recovery_document;
if (manageProvider) {
return (
<AddingProviderScreen onCancel={async () => setManageProvider(false)} />
);
}
if (reducer.discoveryState.state === "none") {
// Can this even happen?
return (
<AnastasisClientFrame title="Recovery: Select secret">
<div>waiting to start discovery</div>
</AnastasisClientFrame>
);
}
if (reducer.discoveryState.state === "active") {
return (
<AnastasisClientFrame title="Recovery: Select secret">
<div>loading secret versions</div>
</AnastasisClientFrame>
);
}
const policies = reducer.discoveryState.aggregatedPolicies ?? [];
if (policies.length === 0) {
return (
<ChooseAnotherProviderScreen
providers={provs}
selected=""
onChange={() => null}
></ChooseAnotherProviderScreen>
);
}
return (
<AnastasisClientFrame
title="Recovery: Select secret"
@ -115,9 +73,7 @@ export function SecretSelectionScreen(): VNode {
<b>Id:</b>&nbsp;
<span
class="icon has-tooltip-top"
data-tooltip={version.policy_hash
.match(/(.{22})/g)
?.join("\n")}
data-tooltip={version.policy_hash}
>
<i class="mdi mdi-information" />
</span>
@ -128,9 +84,7 @@ export function SecretSelectionScreen(): VNode {
<div>
<AsyncButton
class="button"
onClick={() =>
reducer.transition("select_version", version)
}
onClick={async () => onNext(version)}
>
Recover
</AsyncButton>
@ -145,9 +99,7 @@ export function SecretSelectionScreen(): VNode {
challenges solving
</p>
<p class="block">
<a onClick={() => setManageProvider(true)}>
Manage recovery providers
</a>
<a onClick={onManageProvider}>Manage recovery providers</a>
</p>
</div>
</div>
@ -155,8 +107,7 @@ export function SecretSelectionScreen(): VNode {
);
}
export function OldSecretSelectionScreen(): VNode {
const [selectingVersion, setSelectingVersion] = useState<boolean>(false);
export function SecretSelectionScreen(): VNode {
const reducer = useAnastasisContext();
const [manageProvider, setManageProvider] = useState(false);
@ -169,15 +120,10 @@ export function OldSecretSelectionScreen(): VNode {
f().catch((e) => console.log(e));
}, []);
const currentVersion =
(reducer?.currentReducerState &&
"recovery_document" in reducer.currentReducerState &&
reducer.currentReducerState.recovery_document?.version) ||
0;
if (!reducer) {
return <div>no reducer in context</div>;
}
if (
!reducer.currentReducerState ||
reducer.currentReducerState.reducer_type !== "recovery"
@ -185,97 +131,178 @@ export function OldSecretSelectionScreen(): VNode {
return <div>invalid state</div>;
}
async function doSelectVersion(p: string, n: number): Promise<void> {
if (!reducer) return Promise.resolve();
return reducer.runTransaction(async (tx) => {
await tx.transition("select_version", {
version: n,
provider_url: p,
});
setSelectingVersion(false);
});
}
const provs = reducer.currentReducerState.authentication_providers ?? {};
const recoveryDocument = reducer.currentReducerState.recovery_document;
if (!recoveryDocument) {
return (
<ChooseAnotherProviderScreen
providers={provs}
selected=""
onChange={(newProv) => doSelectVersion(newProv, 0)}
/>
);
}
if (selectingVersion) {
return (
<SelectOtherVersionProviderScreen
providers={provs}
provider={recoveryDocument.provider_url}
version={recoveryDocument.version}
onCancel={() => setSelectingVersion(false)}
onConfirm={doSelectVersion}
/>
);
}
if (manageProvider) {
return (
<AddingProviderScreen onCancel={async () => setManageProvider(false)} />
);
}
const providerInfo = provs[
recoveryDocument.provider_url
] as AuthenticationProviderStatusOk;
if (
reducer.discoveryState.state === "none" ||
reducer.discoveryState.state === "active"
) {
// Can this even happen?
return <SecretSelectionScreenWaiting />;
}
const policies = reducer.discoveryState.aggregatedPolicies ?? [];
if (policies.length === 0) {
return (
<AddingProviderScreen
onCancel={async () => setManageProvider(false)}
notifications={[
{
message: "Secret not found",
type: "ERROR",
description:
"With the information you provided we could not found secret in any of the providers. You can try adding more providers if you think the data is correct.",
},
]}
/>
);
}
return (
<AnastasisClientFrame title="Recovery: Select secret">
<div class="columns">
<div class="column">
<div class="box" style={{ border: "2px solid green" }}>
<h1 class="subtitle">{providerInfo.business_name}</h1>
<div class="block">
{currentVersion === 0 ? (
<p>Set to recover the latest version</p>
) : (
<p>Set to recover the version number {currentVersion}</p>
)}
</div>
<div class="buttons is-right">
<button class="button" onClick={(e) => setSelectingVersion(true)}>
Change secret&apos;s version
</button>
</div>
</div>
</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>
<SecretSelectionScreenFound
policies={policies}
onNext={(version) => reducer.transition("select_version", version)}
onManageProvider={async () => setManageProvider(false)}
/>
);
}
// export function OldSecretSelectionScreen(): VNode {
// const [selectingVersion, setSelectingVersion] = useState<boolean>(false);
// const reducer = useAnastasisContext();
// const [manageProvider, setManageProvider] = useState(false);
// useEffect(() => {
// async function f() {
// if (reducer) {
// await reducer.discoverStart();
// }
// }
// f().catch((e) => console.log(e));
// }, []);
// const currentVersion =
// (reducer?.currentReducerState &&
// "recovery_document" in reducer.currentReducerState &&
// reducer.currentReducerState.recovery_document?.version) ||
// 0;
// if (!reducer) {
// return <div>no reducer in context</div>;
// }
// if (
// !reducer.currentReducerState ||
// reducer.currentReducerState.reducer_type !== "recovery"
// ) {
// return <div>invalid state</div>;
// }
// async function doSelectVersion(p: string, n: number): Promise<void> {
// if (!reducer) return Promise.resolve();
// return reducer.runTransaction(async (tx) => {
// await tx.transition("select_version", {
// version: n,
// provider_url: p,
// });
// setSelectingVersion(false);
// });
// }
// const provs = reducer.currentReducerState.authentication_providers ?? {};
// const recoveryDocument = reducer.currentReducerState.recovery_document;
// if (!recoveryDocument) {
// return (
// <ChooseAnotherProviderScreen
// providers={provs}
// selected=""
// onChange={(newProv) => doSelectVersion(newProv, 0)}
// />
// );
// }
// if (selectingVersion) {
// return (
// <SelectOtherVersionProviderScreen
// providers={provs}
// provider={recoveryDocument.provider_url}
// version={recoveryDocument.version}
// onCancel={() => setSelectingVersion(false)}
// onConfirm={doSelectVersion}
// />
// );
// }
// if (manageProvider) {
// return (
// <AddingProviderScreen onCancel={async () => setManageProvider(false)} />
// );
// }
// const providerInfo = provs[
// recoveryDocument.provider_url
// ] as AuthenticationProviderStatusOk;
// return (
// <AnastasisClientFrame title="Recovery: Select secret">
// <div class="columns">
// <div class="column">
// <div class="box" style={{ border: "2px solid green" }}>
// <h1 class="subtitle">{providerInfo.business_name}</h1>
// <div class="block">
// {currentVersion === 0 ? (
// <p>Set to recover the latest version</p>
// ) : (
// <p>Set to recover the version number {currentVersion}</p>
// )}
// </div>
// <div class="buttons is-right">
// <button class="button" onClick={(e) => setSelectingVersion(true)}>
// Change secret&apos;s version
// </button>
// </div>
// </div>
// </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>
// );
// }
function ChooseAnotherProviderScreen({
providers,
selected,
onChange,
}: {
selected: string;
providers: { [url: string]: AuthenticationProviderStatus };
onChange: (prov: string) => void;
}): VNode {
const reducer = useAnastasisContext();
if (!reducer) {
return <div>no reducer in context</div>;
}
if (
!reducer.currentReducerState ||
reducer.currentReducerState.reducer_type !== "recovery"
) {
return <div>invalid state</div>;
}
const providers = reducer.currentReducerState.authentication_providers ?? {};
return (
<AnastasisClientFrame
hideNext="Recovery document not found"
@ -286,13 +313,9 @@ function ChooseAnotherProviderScreen({
<label class="label">Provider</label>
<div class="control is-expanded has-icons-left">
<div class="select is-fullwidth">
<select
onChange={(e) => onChange(e.currentTarget.value)}
value={selected}
>
<select onChange={(e) => onChange(e.currentTarget.value)} value="">
<option key="none" disabled selected value="">
{" "}
Choose a provider{" "}
Choose a provider
</option>
{Object.keys(providers).map((url) => {
const p = providers[url];
@ -419,3 +442,11 @@ function SelectOtherVersionProviderScreen({
</AnastasisClientFrame>
);
}
function SecretSelectionScreenWaiting(): VNode {
return (
<AnastasisClientFrame title="Recovery: Select secret">
<div>loading secret versions</div>
</AnastasisClientFrame>
);
}

View File

@ -40,7 +40,14 @@ export function SolveOverviewFeedbackDisplay(props: {
message: `Message from provider`,
description: (
<span>
To pay you can <a href={feedback.taler_pay_uri}>click here</a>
To pay you can{" "}
<a
href={feedback.taler_pay_uri}
target="_blank"
rel="noreferrer"
>
click here
</a>
</span>
),
},
@ -65,8 +72,12 @@ export function SolveOverviewFeedbackDisplay(props: {
notifications={[
{
type: "ERROR",
message: `Server error: Code ${feedback.http_status}`,
description: feedback.error_response,
message: `Server error: response code ${feedback.http_status}`,
description: !feedback.error_response
? undefined
: `More information: ${JSON.stringify(
feedback.error_response,
)}`,
},
]}
/>
@ -77,8 +88,7 @@ export function SolveOverviewFeedbackDisplay(props: {
notifications={[
{
type: "ERROR",
message: `Message from provider`,
description: "There were to many failed attempts.",
message: "There were to many failed attempts.",
},
]}
/>
@ -107,11 +117,56 @@ export function SolveOverviewFeedbackDisplay(props: {
]}
/>
);
default:
console.warn(
`unknown challenge feedback status ${JSON.stringify(feedback)}`,
case ChallengeFeedbackStatus.CodeInFile:
return (
<Notifications
notifications={[
{
type: "INFO",
message: `Required TAN can be found in file "${feedback.filename}"`,
description: feedback.display_hint
? `HINT: ${feedback.display_hint}`
: undefined,
},
]}
/>
);
case ChallengeFeedbackStatus.CodeSent:
return (
<Notifications
notifications={[
{
type: "INFO",
message: `Code sent to address "${feedback.address_hint}"`,
description: feedback.display_hint
? `HINT: ${feedback.display_hint}`
: undefined,
},
]}
/>
);
case ChallengeFeedbackStatus.IncorrectAnswer:
return (
<Notifications
notifications={[
{
type: "ERROR",
message: `The answer is wrong.`,
},
]}
/>
);
case ChallengeFeedbackStatus.Solved:
return (
<Notifications
notifications={[
{
type: "SUCCESS",
message: `This challenge is solved`,
},
]}
/>
);
return <div />;
}
}

View File

@ -20,7 +20,6 @@
*/
import {
ChallengeFeedbackBankTransferRequired,
ChallengeFeedbackStatus,
ReducerState,
} from "@gnu-taler/anastasis-core";
@ -61,45 +60,111 @@ export const WithoutFeedback = createExample(
},
);
const recovery_information = {
challenges: [
{
instructions: "does P equal NP?",
type: "question",
uuid: "ASDASDSAD!1",
},
],
policies: [],
};
export const CodeInFileFeedback = createExample(TestedComponent[type].solve, {
...reducerStatesExample.challengeSolving,
recovery_information,
selected_challenge_uuid: "ASDASDSAD!1",
challenge_feedback: {
"ASDASDSAD!1": {
state: ChallengeFeedbackStatus.CodeInFile,
filename: "asd",
display_hint: "hint",
},
},
} as ReducerState);
export const CodeSentFeedback = createExample(TestedComponent[type].solve, {
...reducerStatesExample.challengeSolving,
recovery_information,
selected_challenge_uuid: "ASDASDSAD!1",
challenge_feedback: {
"ASDASDSAD!1": {
state: ChallengeFeedbackStatus.CodeSent,
address_hint: "asdasd",
display_hint: "qweqweqw",
},
},
} as ReducerState);
export const SolvedFeedback = createExample(TestedComponent[type].solve, {
...reducerStatesExample.challengeSolving,
recovery_information,
selected_challenge_uuid: "ASDASDSAD!1",
challenge_feedback: {
"ASDASDSAD!1": {
state: ChallengeFeedbackStatus.Solved,
},
},
} as ReducerState);
export const ServerFailureFeedback = createExample(
TestedComponent[type].solve,
{
...reducerStatesExample.challengeSolving,
recovery_information: {
challenges: [
{
instructions: "does P equal NP?",
type: "question",
uuid: "ASDASDSAD!1",
},
],
policies: [],
},
recovery_information,
selected_challenge_uuid: "ASDASDSAD!1",
challenge_feedback: {
"ASDASDSAD!1": {
state: ChallengeFeedbackStatus.ServerFailure,
http_status: 500,
error_response: "Couldn't connect to mysql",
},
},
} as ReducerState,
);
export const MessageRateLimitExceededFeedback = createExample(
export const TruthUnknownFeedback = createExample(TestedComponent[type].solve, {
...reducerStatesExample.challengeSolving,
recovery_information,
selected_challenge_uuid: "ASDASDSAD!1",
challenge_feedback: {
"ASDASDSAD!1": {
state: ChallengeFeedbackStatus.TruthUnknown,
},
},
} as ReducerState);
export const TalerPaymentFeedback = createExample(TestedComponent[type].solve, {
...reducerStatesExample.challengeSolving,
recovery_information,
selected_challenge_uuid: "ASDASDSAD!1",
challenge_feedback: {
"ASDASDSAD!1": {
state: ChallengeFeedbackStatus.TalerPayment,
payment_secret: "secret",
provider: "asdasdas",
taler_pay_uri: "taler://pay/...",
},
},
} as ReducerState);
export const UnsupportedFeedback = createExample(TestedComponent[type].solve, {
...reducerStatesExample.challengeSolving,
recovery_information,
selected_challenge_uuid: "ASDASDSAD!1",
challenge_feedback: {
"ASDASDSAD!1": {
state: ChallengeFeedbackStatus.Unsupported,
unsupported_method: "method",
},
},
} as ReducerState);
export const RateLimitExceededFeedback = createExample(
TestedComponent[type].solve,
{
...reducerStatesExample.challengeSolving,
recovery_information: {
challenges: [
{
instructions: "does P equals NP?",
type: "question",
uuid: "ASDASDSAD!1",
},
],
policies: [],
},
recovery_information,
selected_challenge_uuid: "ASDASDSAD!1",
challenge_feedback: {
"ASDASDSAD!1": {
@ -109,94 +174,76 @@ export const MessageRateLimitExceededFeedback = createExample(
} as ReducerState,
);
export const UnsupportedFeedback = createExample(TestedComponent[type].solve, {
...reducerStatesExample.challengeSolving,
recovery_information: {
challenges: [
{
instructions: "does P equals NP?",
type: "question",
uuid: "ASDASDSAD!1",
export const IbanInstructionsFeedback = createExample(
TestedComponent[type].solve,
{
...reducerStatesExample.challengeSolving,
recovery_information,
selected_challenge_uuid: "ASDASDSAD!1",
challenge_feedback: {
"ASDASDSAD!1": {
state: ChallengeFeedbackStatus.IbanInstructions,
challenge_amount: "EUR:1",
target_iban: "DE12345789000",
target_business_name: "Data Loss Incorporated",
wire_transfer_subject: "Anastasis 987654321",
answer_code: 987654321,
},
],
policies: [],
},
selected_challenge_uuid: "ASDASDSAD!1",
challenge_feedback: {
"ASDASDSAD!1": {
state: ChallengeFeedbackStatus.Unsupported,
http_status: 500,
unsupported_method: "Question",
},
},
} as ReducerState);
} as ReducerState,
);
export const TruthUnknownFeedback = createExample(TestedComponent[type].solve, {
...reducerStatesExample.challengeSolving,
recovery_information: {
challenges: [
{
instructions: "does P equals NP?",
type: "question",
uuid: "ASDASDSAD!1",
export const IncorrectAnswerFeedback = createExample(
TestedComponent[type].solve,
{
...reducerStatesExample.challengeSolving,
recovery_information,
selected_challenge_uuid: "ASDASDSAD!1",
challenge_feedback: {
"ASDASDSAD!1": {
state: ChallengeFeedbackStatus.IncorrectAnswer,
},
],
policies: [],
},
selected_challenge_uuid: "ASDASDSAD!1",
challenge_feedback: {
"ASDASDSAD!1": {
state: ChallengeFeedbackStatus.TruthUnknown,
},
},
} as ReducerState);
} as ReducerState,
);
const ibanFeedback: ChallengeFeedbackBankTransferRequired = {
state: ChallengeFeedbackStatus.IbanInstructions,
challenge_amount: "EUR:1",
target_iban: "DE12345789000",
target_business_name: "Data Loss Incorporated",
wire_transfer_subject: "Anastasis 987654321",
answer_code: 987654321,
};
// export const AuthIbanFeedback = createExample(TestedComponent[type].solve, {
// ...reducerStatesExample.challengeSolving,
// recovery_information: {
// challenges: [
// {
// instructions: "does P equals NP?",
// type: "question",
// uuid: "ASDASDSAD!1",
// },
// ],
// policies: [],
// },
// selected_challenge_uuid: "ASDASDSAD!1",
// challenge_feedback: {
// "ASDASDSAD!1": ibanFeedback,
// },
// } as ReducerState);
export const AuthIbanFeedback = createExample(TestedComponent[type].solve, {
...reducerStatesExample.challengeSolving,
recovery_information: {
challenges: [
{
instructions: "does P equals NP?",
type: "question",
uuid: "ASDASDSAD!1",
},
],
policies: [],
},
selected_challenge_uuid: "ASDASDSAD!1",
challenge_feedback: {
"ASDASDSAD!1": ibanFeedback,
},
} as ReducerState);
export const PaymentFeedback = createExample(TestedComponent[type].solve, {
...reducerStatesExample.challengeSolving,
recovery_information: {
challenges: [
{
instructions: "does P equals NP?",
type: "question",
uuid: "ASDASDSAD!1",
},
],
policies: [],
},
selected_challenge_uuid: "ASDASDSAD!1",
challenge_feedback: {
"ASDASDSAD!1": {
state: ChallengeFeedbackStatus.TalerPayment,
taler_pay_uri: "taler://pay/...",
provider: "https://localhost:8080/",
payment_secret: "3P4561HAMHRRYEYD6CM6J7TS5VTD5SR2K2EXJDZEFSX92XKHR4KG",
},
},
} as ReducerState);
// export const PaymentFeedback = createExample(TestedComponent[type].solve, {
// ...reducerStatesExample.challengeSolving,
// recovery_information: {
// challenges: [
// {
// instructions: "does P equals NP?",
// type: "question",
// uuid: "ASDASDSAD!1",
// },
// ],
// policies: [],
// },
// selected_challenge_uuid: "ASDASDSAD!1",
// challenge_feedback: {
// "ASDASDSAD!1": {
// state: ChallengeFeedbackStatus.TalerPayment,
// taler_pay_uri: "taler://pay/...",
// provider: "https://localhost:8080/",
// payment_secret: "3P4561HAMHRRYEYD6CM6J7TS5VTD5SR2K2EXJDZEFSX92XKHR4KG",
// },
// },
// } as ReducerState);

View File

@ -20,7 +20,7 @@
*/
export * as AddingProviderScreen from "./AddingProviderScreen/stories.js";
export * as algo from "./AttributeEntryScreen.stories.js";
export * as AttributeEntryScreen from "./AttributeEntryScreen.stories.js";
export * as AuthenticationEditorScreen from "./AuthenticationEditorScreen.stories.js";
export * as authMethod_AuthMethodEmailSetup from "./authMethod/AuthMethodEmailSetup.stories.js";

View File

@ -85,7 +85,7 @@ function ErrorBoundary(props: {
children: ComponentChildren;
}): VNode {
const [error, resetError] = useErrorBoundary((error) =>
console.log("got error", error),
console.log("ErrorBoundary got error", error),
);
if (error) {
return (
@ -132,7 +132,7 @@ export function AnastasisClientFrame(props: AnastasisClientFrameProps): VNode {
history.pushState({ id: nextId }, "unused", `#${nextId}`);
} catch (e) {
console.log(e);
console.log("ERROR doNext ", e);
}
}

View File

@ -38,7 +38,6 @@ function parseExampleImport(
im: any,
name?: string,
): ComponentItem {
console.log(im);
const component = name || im.default.title;
const order: number = im.default.args?.order || 0;
return {
@ -372,9 +371,8 @@ function LiveReload({ port = 8002 }: { port?: number }): VNode {
}
function setupLiveReload(port: number, onReload: () => void): void {
const protocol = location.protocol === "https:" ? "wss:" : "ws:";
const host = location.hostname;
const socketPath = `${protocol}//${host}:${port}/socket`;
const socketPath = `ws://localhost:8003/socket`;
// const socketPath = `${protocol}//${host}:${port}/socket`;
const ws = new WebSocket(socketPath);
ws.onmessage = (message) => {

View File

@ -54,7 +54,7 @@ export function createExample<Props>(
discoverMore: noop,
discoverStart: noop,
discoveryState: {
state: "none",
state: "finished",
},
currentError: undefined,
back: noop,
@ -204,14 +204,17 @@ const base = {
} as AuthenticationProviderStatusOk,
"http://localhost:8087/": {
status: "error",
code: 8414,
hint: "request to provider failed",
} as AuthenticationProviderStatusError,
"http://localhost:8088/": {
status: "error",
code: 8414,
hint: "request to provider failed",
} as AuthenticationProviderStatusError,
"http://localhost:8089/": {
status: "error",
code: 8414,
hint: "request to provider failed",
} as AuthenticationProviderStatusError,

View File

@ -1,4 +1,7 @@
#!/bin/bash
#clean up
rm /tmp/send_signal
socat TCP-LISTEN:8003,fork,reuseaddr,keepalive EXEC:"./watch/reply.sh"