summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Dold <florian@dold.me>2022-04-13 19:32:12 +0200
committerFlorian Dold <florian@dold.me>2022-04-13 19:32:17 +0200
commit5054ff6c6d200e8d4d7658e001b0bcb1936d6876 (patch)
tree325c7ad151554cc5927c266f0331eb4fdad57516
parentec9aed276a5c837a9a93bae2a4c2e61d77256cc1 (diff)
downloadwallet-core-5054ff6c6d200e8d4d7658e001b0bcb1936d6876.tar.gz
wallet-core-5054ff6c6d200e8d4d7658e001b0bcb1936d6876.tar.bz2
wallet-core-5054ff6c6d200e8d4d7658e001b0bcb1936d6876.zip
anastasis-webui: make TOTP work again
-rw-r--r--packages/anastasis-core/src/index.ts4
-rw-r--r--packages/anastasis-webui/package.json1
-rw-r--r--packages/anastasis-webui/preact.config.js2
-rw-r--r--packages/anastasis-webui/src/components/menu/LangSelector.tsx2
-rw-r--r--packages/anastasis-webui/src/components/menu/SideBar.tsx6
-rw-r--r--packages/anastasis-webui/src/hooks/use-anastasis-reducer.ts16
-rw-r--r--packages/anastasis-webui/src/pages/home/AttributeEntryScreen.tsx7
-rw-r--r--packages/anastasis-webui/src/pages/home/authMethod/AuthMethodTotpSetup.tsx13
-rw-r--r--packages/anastasis-webui/src/pages/home/authMethod/AuthMethodTotpSolve.tsx4
-rw-r--r--packages/anastasis-webui/src/pages/home/index.tsx75
-rw-r--r--packages/anastasis-webui/src/utils/index.tsx5
11 files changed, 93 insertions, 42 deletions
diff --git a/packages/anastasis-core/src/index.ts b/packages/anastasis-core/src/index.ts
index 68ecc5173..98aba2ce6 100644
--- a/packages/anastasis-core/src/index.ts
+++ b/packages/anastasis-core/src/index.ts
@@ -14,7 +14,6 @@ import {
getRandomBytes,
hash,
HttpStatusCode,
- j2s,
Logger,
parsePayUri,
stringToBytes,
@@ -27,8 +26,7 @@ import {
import { anastasisData } from "./anastasis-data.js";
import {
EscrowConfigurationResponse,
- IbanExternalAuthResponse,
- RecoveryMetaResponse as RecoveryMetaResponse,
+ RecoveryMetaResponse,
TruthUploadRequest,
} from "./provider-types.js";
import {
diff --git a/packages/anastasis-webui/package.json b/packages/anastasis-webui/package.json
index 96ff60b41..2327b5e12 100644
--- a/packages/anastasis-webui/package.json
+++ b/packages/anastasis-webui/package.json
@@ -15,6 +15,7 @@
"pretty": "prettier --write src",
"storybook": "start-storybook -p 6006"
},
+ "type": "module",
"eslintConfig": {
"parser": "@typescript-eslint/parser",
"extends": [
diff --git a/packages/anastasis-webui/preact.config.js b/packages/anastasis-webui/preact.config.js
index f9a8d6cba..3f6b69016 100644
--- a/packages/anastasis-webui/preact.config.js
+++ b/packages/anastasis-webui/preact.config.js
@@ -28,7 +28,7 @@ const commitHash = cp.execSync("git rev-parse --short HEAD").toString();
export default {
webpack(config, env, helpers) {
- // add __VERSION__ to be use in the html
+ // add __VERSION__ to be used in the html
config.plugins.push(
new DefinePlugin({
"process.env.__VERSION__": JSON.stringify(
diff --git a/packages/anastasis-webui/src/components/menu/LangSelector.tsx b/packages/anastasis-webui/src/components/menu/LangSelector.tsx
index fa22a29c0..3566f0c26 100644
--- a/packages/anastasis-webui/src/components/menu/LangSelector.tsx
+++ b/packages/anastasis-webui/src/components/menu/LangSelector.tsx
@@ -23,7 +23,7 @@ import { h, VNode } from "preact";
import { useState } from "preact/hooks";
import langIcon from "../../assets/icons/languageicon.svg";
import { useTranslationContext } from "../../context/translation";
-import { strings as messages } from "../../i18n/strings";
+import { strings as messages } from "../../i18n/strings.js";
type LangsNames = {
[P in keyof typeof messages]: string;
diff --git a/packages/anastasis-webui/src/components/menu/SideBar.tsx b/packages/anastasis-webui/src/components/menu/SideBar.tsx
index 023b2b63c..e265a817d 100644
--- a/packages/anastasis-webui/src/components/menu/SideBar.tsx
+++ b/packages/anastasis-webui/src/components/menu/SideBar.tsx
@@ -78,8 +78,7 @@ export function Sidebar({ mobile }: Props): VNode {
</div>
</li>
)}
- {reducer.currentReducerState &&
- reducer.currentReducerState.backup_state ? (
+ {reducer.currentReducerState?.reducer_type === "backup" ? (
<Fragment>
<li
class={
@@ -191,8 +190,7 @@ export function Sidebar({ mobile }: Props): VNode {
</li>
</Fragment>
) : (
- reducer.currentReducerState &&
- reducer.currentReducerState?.recovery_state && (
+ reducer.currentReducerState?.reducer_type === "recovery" && (
<Fragment>
<li
class={
diff --git a/packages/anastasis-webui/src/hooks/use-anastasis-reducer.ts b/packages/anastasis-webui/src/hooks/use-anastasis-reducer.ts
index b1c17eb96..7274c3d03 100644
--- a/packages/anastasis-webui/src/hooks/use-anastasis-reducer.ts
+++ b/packages/anastasis-webui/src/hooks/use-anastasis-reducer.ts
@@ -199,7 +199,7 @@ export function useAnastasisReducer(): AnastasisReducerApi {
s = await reduceAction(anastasisState.reducerState!, action, args);
}
console.log("got response from reducer", s);
- if (s.code) {
+ if (s.reducer_type === "error") {
console.log("response is an error");
setAnastasisState({ ...anastasisState, currentError: s });
} else {
@@ -223,7 +223,7 @@ export function useAnastasisReducer(): AnastasisReducerApi {
} else {
s = await getBackupStartState();
}
- if (s.code !== undefined) {
+ if (s.reducer_type === "error") {
setAnastasisState({
...anastasisState,
currentError: s,
@@ -274,7 +274,7 @@ export function useAnastasisReducer(): AnastasisReducerApi {
} else {
s = await getRecoveryStartState();
}
- if (s.code !== undefined) {
+ if (s.reducer_type === "error") {
setAnastasisState({
...anastasisState,
currentError: s,
@@ -296,8 +296,10 @@ export function useAnastasisReducer(): AnastasisReducerApi {
return;
}
if (
- reducerState.backup_state === BackupStates.ContinentSelecting ||
- reducerState.recovery_state === RecoveryStates.ContinentSelecting
+ (reducerState.reducer_type === "backup" &&
+ reducerState.backup_state === BackupStates.ContinentSelecting) ||
+ (reducerState.reducer_type === "recovery" &&
+ reducerState.recovery_state === RecoveryStates.ContinentSelecting)
) {
setAnastasisState({
...anastasisState,
@@ -327,7 +329,7 @@ export function useAnastasisReducer(): AnastasisReducerApi {
}
const s = txHandle.transactionState;
console.log("transaction finished, new state", s);
- if (s.code !== undefined) {
+ if (s.reducer_type === "error") {
setAnastasisState({
...anastasisState,
currentError: txHandle.transactionState,
@@ -355,7 +357,7 @@ class ReducerTxImpl implements ReducerTransactionHandle {
console.log("making transition in transaction", action);
this.transactionState = s;
// Abort transaction as soon as we transition into an error state.
- if (this.transactionState.code !== undefined) {
+ if (this.transactionState.reducer_type === "error") {
throw Error("transition resulted in error");
}
return this.transactionState;
diff --git a/packages/anastasis-webui/src/pages/home/AttributeEntryScreen.tsx b/packages/anastasis-webui/src/pages/home/AttributeEntryScreen.tsx
index 501415c40..257c28075 100644
--- a/packages/anastasis-webui/src/pages/home/AttributeEntryScreen.tsx
+++ b/packages/anastasis-webui/src/pages/home/AttributeEntryScreen.tsx
@@ -1,6 +1,6 @@
import { UserAttributeSpec, validators } from "@gnu-taler/anastasis-core";
import { isAfter, parse } from "date-fns";
-import { Fragment, h, VNode } from "preact";
+import { h, VNode } from "preact";
import { useState } from "preact/hooks";
import { DateInput } from "../../components/fields/DateInput";
import { PhoneNumberInput } from "../../components/fields/NumberInput";
@@ -72,7 +72,10 @@ export function AttributeEntryScreen(): VNode {
const doConfirm = async () => {
await reducer.transition("enter_user_attributes", {
- identity_attributes: attrs,
+ identity_attributes: {
+ application_id: "anastasis-standalone",
+ ...attrs,
+ },
});
};
diff --git a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodTotpSetup.tsx b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodTotpSetup.tsx
index e0f0cc5e2..a191fb9e6 100644
--- a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodTotpSetup.tsx
+++ b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodTotpSetup.tsx
@@ -7,6 +7,11 @@ import { TextInput } from "../../../components/fields/TextInput";
import { QR } from "../../../components/QR";
import { base32enc, computeTOTPandCheck } from "./totp";
+/**
+ * This is hard-coded in the protocol for TOTP auth.
+ */
+const ANASTASIS_TOTP_DIGITS = 8;
+
export function AuthMethodTotpSetup({
addAuthMethod,
cancel,
@@ -14,20 +19,20 @@ export function AuthMethodTotpSetup({
}: AuthMethodSetupProps): VNode {
const [name, setName] = useState("anastasis");
const [test, setTest] = useState("");
- const digits = 8;
const secretKey = useMemo(() => {
const array = new Uint8Array(32);
return window.crypto.getRandomValues(array);
}, []);
+
const secret32 = base32enc(secretKey);
- const totpURL = `otpauth://totp/${name}?digits=${digits}&secret=${secret32}`;
+ const totpURL = `otpauth://totp/${name}?digits=${ANASTASIS_TOTP_DIGITS}&secret=${secret32}`;
const addTotpAuth = (): void =>
addAuthMethod({
authentication_method: {
type: "totp",
- instructions: `Enter ${digits} digits code for "${name}"`,
- challenge: encodeCrock(stringToBytes(totpURL)),
+ instructions: `Enter ${ANASTASIS_TOTP_DIGITS} digits code for "${name}"`,
+ challenge: encodeCrock(secretKey),
},
});
diff --git a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodTotpSolve.tsx b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodTotpSolve.tsx
index ce7b2e545..ee4937441 100644
--- a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodTotpSolve.tsx
+++ b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodTotpSolve.tsx
@@ -11,7 +11,7 @@ import { AnastasisClientFrame } from "../index";
import { SolveOverviewFeedbackDisplay } from "../SolveScreen";
import { AuthMethodSolveProps } from "./index";
-export function AuthMethodTotpSolve({ id }: AuthMethodSolveProps): VNode {
+export function AuthMethodTotpSolve(props: AuthMethodSolveProps): VNode {
const [answerCode, setAnswerCode] = useState("");
const reducer = useAnastasisContext();
@@ -74,7 +74,7 @@ export function AuthMethodTotpSolve({ id }: AuthMethodSolveProps): VNode {
async function onNext(): Promise<void> {
console.log(`sending TOTP code '${answerCode}'`);
return reducer?.transition("solve_challenge", {
- pin: Number.parseInt(answerCode),
+ answer: answerCode,
});
}
function onCancel(): void {
diff --git a/packages/anastasis-webui/src/pages/home/index.tsx b/packages/anastasis-webui/src/pages/home/index.tsx
index ca6da8474..7d191ae04 100644
--- a/packages/anastasis-webui/src/pages/home/index.tsx
+++ b/packages/anastasis-webui/src/pages/home/index.tsx
@@ -34,7 +34,7 @@ import { StartScreen } from "./StartScreen";
import { TruthsPayingScreen } from "./TruthsPayingScreen";
function isBackup(reducer: AnastasisReducerApi): boolean {
- return !!reducer.currentReducerState?.backup_state;
+ return reducer.currentReducerState?.reducer_type === "backup";
}
export function withProcessLabel(
@@ -171,57 +171,96 @@ function AnastasisClientImpl(): VNode {
console.log("state", reducer.currentReducerState);
if (
- state.backup_state === BackupStates.ContinentSelecting ||
- state.recovery_state === RecoveryStates.ContinentSelecting ||
- state.backup_state === BackupStates.CountrySelecting ||
- state.recovery_state === RecoveryStates.CountrySelecting
+ (state.reducer_type === "backup" &&
+ state.backup_state === BackupStates.ContinentSelecting) ||
+ (state.reducer_type === "recovery" &&
+ state.recovery_state === RecoveryStates.ContinentSelecting) ||
+ (state.reducer_type === "backup" &&
+ state.backup_state === BackupStates.CountrySelecting) ||
+ (state.reducer_type === "recovery" &&
+ state.recovery_state === RecoveryStates.CountrySelecting)
) {
return <ContinentSelectionScreen />;
}
if (
- state.backup_state === BackupStates.UserAttributesCollecting ||
- state.recovery_state === RecoveryStates.UserAttributesCollecting
+ (state.reducer_type === "backup" &&
+ state.backup_state === BackupStates.UserAttributesCollecting) ||
+ (state.reducer_type === "recovery" &&
+ state.recovery_state === RecoveryStates.UserAttributesCollecting)
) {
return <AttributeEntryScreen />;
}
- if (state.backup_state === BackupStates.AuthenticationsEditing) {
+ if (
+ state.reducer_type === "backup" &&
+ state.backup_state === BackupStates.AuthenticationsEditing
+ ) {
return <AuthenticationEditorScreen />;
}
- if (state.backup_state === BackupStates.PoliciesReviewing) {
+ if (
+ state.reducer_type === "backup" &&
+ state.backup_state === BackupStates.PoliciesReviewing
+ ) {
return <ReviewPoliciesScreen />;
}
- if (state.backup_state === BackupStates.SecretEditing) {
+ if (
+ state.reducer_type === "backup" &&
+ state.backup_state === BackupStates.SecretEditing
+ ) {
return <SecretEditorScreen />;
}
- if (state.backup_state === BackupStates.BackupFinished) {
+ if (
+ state.reducer_type === "backup" &&
+ state.backup_state === BackupStates.BackupFinished
+ ) {
return <BackupFinishedScreen />;
}
- if (state.backup_state === BackupStates.TruthsPaying) {
+ if (
+ state.reducer_type === "backup" &&
+ state.backup_state === BackupStates.TruthsPaying
+ ) {
return <TruthsPayingScreen />;
}
- if (state.backup_state === BackupStates.PoliciesPaying) {
+ if (
+ state.reducer_type === "backup" &&
+ state.backup_state === BackupStates.PoliciesPaying
+ ) {
return <PoliciesPayingScreen />;
}
- if (state.recovery_state === RecoveryStates.SecretSelecting) {
+ if (
+ state.reducer_type === "recovery" &&
+ state.recovery_state === RecoveryStates.SecretSelecting
+ ) {
return <SecretSelectionScreen />;
}
- if (state.recovery_state === RecoveryStates.ChallengeSelecting) {
+ if (
+ state.reducer_type === "recovery" &&
+ state.recovery_state === RecoveryStates.ChallengeSelecting
+ ) {
return <ChallengeOverviewScreen />;
}
- if (state.recovery_state === RecoveryStates.ChallengeSolving) {
+ if (
+ state.reducer_type === "recovery" &&
+ state.recovery_state === RecoveryStates.ChallengeSolving
+ ) {
return <SolveScreen />;
}
- if (state.recovery_state === RecoveryStates.RecoveryFinished) {
+ if (
+ state.reducer_type === "recovery" &&
+ state.recovery_state === RecoveryStates.RecoveryFinished
+ ) {
return <RecoveryFinishedScreen />;
}
- if (state.recovery_state === RecoveryStates.ChallengePaying) {
+ if (
+ state.reducer_type === "recovery" &&
+ state.recovery_state === RecoveryStates.ChallengePaying
+ ) {
return <ChallengePayingScreen />;
}
console.log("unknown state", reducer.currentReducerState);
diff --git a/packages/anastasis-webui/src/utils/index.tsx b/packages/anastasis-webui/src/utils/index.tsx
index 2209fd974..51a074fe9 100644
--- a/packages/anastasis-webui/src/utils/index.tsx
+++ b/packages/anastasis-webui/src/utils/index.tsx
@@ -17,6 +17,11 @@ export function createExample<Props>(
<AnastasisProvider
value={{
currentReducerState,
+ discoverMore: async () => {},
+ discoverStart: async () => {},
+ discoveryState: {
+ state: "none",
+ },
currentError: undefined,
back: async () => {
null;