aboutsummaryrefslogtreecommitdiff
path: root/packages
diff options
context:
space:
mode:
authorFlorian Dold <florian@dold.me>2022-04-13 08:44:37 +0200
committerFlorian Dold <florian@dold.me>2022-04-13 08:44:37 +0200
commitb28583ba7e3be7e4f69aaf543d087b6446f50cf0 (patch)
tree3266e5187384370a403cb339bf34ee378a06e757 /packages
parentf3d8b4474302a00fd923581046b0f5828a4c5976 (diff)
anastasis: tag state properly
Diffstat (limited to 'packages')
-rw-r--r--packages/anastasis-core/src/index.ts44
-rw-r--r--packages/anastasis-core/src/reducer-types.ts46
-rw-r--r--packages/anastasis-webui/src/pages/home/AttributeEntryScreen.tsx2
-rw-r--r--packages/anastasis-webui/src/pages/home/AuthenticationEditorScreen.tsx7
-rw-r--r--packages/anastasis-webui/src/pages/home/BackupFinishedScreen.tsx5
-rw-r--r--packages/anastasis-webui/src/pages/home/ChallengeOverviewScreen.tsx5
-rw-r--r--packages/anastasis-webui/src/pages/home/ChallengePayingScreen.tsx5
-rw-r--r--packages/anastasis-webui/src/pages/home/EditPoliciesScreen.tsx5
-rw-r--r--packages/anastasis-webui/src/pages/home/PoliciesPayingScreen.tsx5
-rw-r--r--packages/anastasis-webui/src/pages/home/RecoveryFinishedScreen.tsx5
-rw-r--r--packages/anastasis-webui/src/pages/home/ReviewPoliciesScreen.tsx5
-rw-r--r--packages/anastasis-webui/src/pages/home/SecretEditorScreen.tsx5
-rw-r--r--packages/anastasis-webui/src/pages/home/SecretSelectionScreen.tsx13
-rw-r--r--packages/anastasis-webui/src/pages/home/SolveScreen.tsx5
-rw-r--r--packages/anastasis-webui/src/pages/home/TruthsPayingScreen.tsx5
15 files changed, 81 insertions, 81 deletions
diff --git a/packages/anastasis-core/src/index.ts b/packages/anastasis-core/src/index.ts
index 542e7eafb..5896dc655 100644
--- a/packages/anastasis-core/src/index.ts
+++ b/packages/anastasis-core/src/index.ts
@@ -196,6 +196,7 @@ function getCountries(
export async function getBackupStartState(): Promise<ReducerStateBackup> {
return {
+ reducer_type: "backup",
backup_state: BackupStates.ContinentSelecting,
continents: getContinents({
requireProvider: true,
@@ -205,6 +206,7 @@ export async function getBackupStartState(): Promise<ReducerStateBackup> {
export async function getRecoveryStartState(): Promise<ReducerStateRecovery> {
return {
+ reducer_type: "recovery",
recovery_state: RecoveryStates.ContinentSelecting,
continents: getContinents({
requireProvider: true,
@@ -571,6 +573,7 @@ async function uploadSecret(
const talerPayUri = resp.headers.get("Taler");
if (!talerPayUri) {
return {
+ reducer_type: "error",
code: TalerErrorCode.ANASTASIS_REDUCER_BACKEND_FAILURE,
hint: `payment requested, but no taler://pay URI given`,
};
@@ -579,6 +582,7 @@ async function uploadSecret(
const parsedUri = parsePayUri(talerPayUri);
if (!parsedUri) {
return {
+ reducer_type: "error",
code: TalerErrorCode.ANASTASIS_REDUCER_BACKEND_FAILURE,
hint: `payment requested, but no taler://pay URI given`,
};
@@ -587,6 +591,7 @@ async function uploadSecret(
continue;
}
return {
+ reducer_type: "error",
code: TalerErrorCode.ANASTASIS_REDUCER_NETWORK_FAILED,
hint: `could not upload truth (HTTP status ${resp.status})`,
};
@@ -674,6 +679,7 @@ async function uploadSecret(
const talerPayUri = resp.headers.get("Taler");
if (!talerPayUri) {
return {
+ reducer_type: "error",
code: TalerErrorCode.ANASTASIS_REDUCER_BACKEND_FAILURE,
hint: `payment requested, but no taler://pay URI given`,
};
@@ -682,6 +688,7 @@ async function uploadSecret(
const parsedUri = parsePayUri(talerPayUri);
if (!parsedUri) {
return {
+ reducer_type: "error",
code: TalerErrorCode.ANASTASIS_REDUCER_BACKEND_FAILURE,
hint: `payment requested, but no taler://pay URI given`,
};
@@ -690,6 +697,7 @@ async function uploadSecret(
continue;
}
return {
+ reducer_type: "error",
code: TalerErrorCode.ANASTASIS_REDUCER_NETWORK_FAILED,
hint: `could not upload policy (http status ${resp.status})`,
};
@@ -734,13 +742,13 @@ async function downloadPolicy(
throw Error("invalid state");
}
for (const prov of state.selected_version.providers) {
- const pi = state.authentication_providers?.[prov.provider_url];
+ const pi = state.authentication_providers?.[prov.url];
if (!pi || pi.status !== "ok") {
continue;
}
const userId = await userIdentifierDerive(userAttributes, pi.salt);
const acctKeypair = accountKeypairDerive(userId);
- const reqUrl = new URL(`policy/${acctKeypair.pub}`, prov.provider_url);
+ const reqUrl = new URL(`policy/${acctKeypair.pub}`, prov.url);
reqUrl.searchParams.set("version", `${prov.version}`);
const resp = await fetch(reqUrl.href);
if (resp.status !== 200) {
@@ -759,7 +767,7 @@ async function downloadPolicy(
policyVersion = Number(resp.headers.get("Anastasis-Version") ?? "0");
} catch (e) {}
foundRecoveryInfo = {
- provider_url: prov.provider_url,
+ provider_url: prov.url,
secret_name: rd.secret_name ?? "<unknown>",
version: policyVersion,
};
@@ -768,6 +776,7 @@ async function downloadPolicy(
}
if (!foundRecoveryInfo || !recoveryDoc) {
return {
+ reducer_type: "error",
code: TalerErrorCode.ANASTASIS_REDUCER_POLICY_LOOKUP_FAILED,
hint: "No backups found at any provider for your identity information.",
};
@@ -874,7 +883,7 @@ async function pollChallenges(
const s2 = await requestTruth(state, truth, {
pin: feedback.answer_code,
});
- if (s2.recovery_state) {
+ if (s2.reducer_type === "recovery") {
state = s2;
}
}
@@ -1001,6 +1010,7 @@ async function requestTruth(
}
return {
+ reducer_type: "error",
code: TalerErrorCode.ANASTASIS_TRUTH_CHALLENGE_FAILED,
hint: "got unexpected /truth/ response status",
http_status: resp.status,
@@ -1110,6 +1120,7 @@ async function selectChallenge(
// FIXME: look at response, include in challenge_feedback!
return {
+ reducer_type: "error",
code: TalerErrorCode.ANASTASIS_TRUTH_CHALLENGE_FAILED,
hint: "got unexpected /truth/.../challenge response status",
http_status: resp.status,
@@ -1125,6 +1136,7 @@ async function backupSelectContinent(
});
if (countries.length <= 0) {
return {
+ reducer_type: "error",
code: TalerErrorCode.ANASTASIS_REDUCER_INPUT_INVALID,
hint: "continent not found",
};
@@ -1423,10 +1435,14 @@ async function nextFromChallengeSelecting(
args: void,
): Promise<ReducerStateRecovery | ReducerStateError> {
const s2 = await tryRecoverSecret(state);
- if (s2.recovery_state === RecoveryStates.RecoveryFinished) {
+ if (
+ s2.reducer_type === "recovery" &&
+ s2.recovery_state === RecoveryStates.RecoveryFinished
+ ) {
return s2;
}
return {
+ reducer_type: "error",
code: TalerErrorCode.ANASTASIS_REDUCER_ACTION_INVALID,
hint: "Not enough challenges solved",
};
@@ -1462,7 +1478,7 @@ export function mergeDiscoveryAggregate(
const oldIndex = polHashToIndex[pol.policy_hash];
if (oldIndex != null) {
aggregatedPolicies[oldIndex].providers.push({
- provider_url: pol.provider_url,
+ url: pol.provider_url,
version: pol.version,
});
} else {
@@ -1471,7 +1487,7 @@ export function mergeDiscoveryAggregate(
policy_hash: pol.policy_hash,
providers: [
{
- provider_url: pol.provider_url,
+ url: pol.provider_url,
version: pol.version,
},
],
@@ -1592,7 +1608,7 @@ const recoveryTransitions: Record<
...transition("add_provider", codecForAny(), addProviderRecovery),
...transition("delete_provider", codecForAny(), deleteProviderRecovery),
...transition(
- "change_version",
+ "select_version",
codecForActionArgsChangeVersion(),
changeVersion,
),
@@ -1621,7 +1637,7 @@ export async function discoverPolicies(
state: ReducerState,
cursor?: DiscoveryCursor,
): Promise<DiscoveryResult> {
- if (!state.recovery_state) {
+ if (state.reducer_type !== "recovery") {
throw Error("can only discover providers in recovery state");
}
@@ -1685,12 +1701,14 @@ export async function reduceAction(
h = recoveryTransitions[state.recovery_state][action];
} else {
return {
+ reducer_type: "error",
code: TalerErrorCode.ANASTASIS_REDUCER_ACTION_INVALID,
hint: `Invalid state (needs backup_state or recovery_state)`,
};
}
if (!h) {
return {
+ reducer_type: "error",
code: TalerErrorCode.ANASTASIS_REDUCER_ACTION_INVALID,
hint: `Unsupported action '${action}' in state '${stateName}'`,
};
@@ -1700,9 +1718,10 @@ export async function reduceAction(
parsedArgs = h.argCodec.decode(args);
} catch (e: any) {
return {
+ reducer_type: "error",
code: TalerErrorCode.ANASTASIS_REDUCER_INPUT_INVALID,
hint: "argument validation failed",
- message: e.toString(),
+ detail: e.toString(),
};
}
try {
@@ -1710,7 +1729,10 @@ export async function reduceAction(
} catch (e) {
logger.error("action handler failed");
if (e instanceof ReducerError) {
- return e.errorJson;
+ return {
+ reducer_type: "error",
+ ...e.errorJson,
+ }
}
throw e;
}
diff --git a/packages/anastasis-core/src/reducer-types.ts b/packages/anastasis-core/src/reducer-types.ts
index 7e8d4da25..03b40e4bd 100644
--- a/packages/anastasis-core/src/reducer-types.ts
+++ b/packages/anastasis-core/src/reducer-types.ts
@@ -73,19 +73,30 @@ export interface CoreSecret {
}
export interface ReducerStateBackup {
- recovery_state?: undefined;
+ reducer_type: "backup";
+
backup_state: BackupStates;
- code?: undefined;
+
currencies?: string[];
+
continents?: ContinentInfo[];
+
countries?: CountryInfo[];
+
identity_attributes?: { [n: string]: string };
+
authentication_providers?: { [url: string]: AuthenticationProviderStatus };
+
authentication_methods?: AuthMethod[];
+
required_attributes?: UserAttributeSpec[];
+
selected_continent?: string;
+
selected_country?: string;
+
secret_name?: string;
+
policies?: Policy[];
recovery_data?: {
@@ -179,17 +190,9 @@ export interface RecoveryInformation {
}
export interface ReducerStateRecovery {
- recovery_state: RecoveryStates;
+ reducer_type: "recovery";
- /**
- * Unused in the recovery states.
- */
- backup_state?: undefined;
-
- /**
- * Unused in the recovery states.
- */
- code?: undefined;
+ recovery_state: RecoveryStates;
identity_attributes?: { [n: string]: string };
@@ -267,11 +270,10 @@ export interface TruthMetaData {
}
export interface ReducerStateError {
- backup_state?: undefined;
- recovery_state?: undefined;
+ reducer_type: "error";
code: number;
hint?: string;
- message?: string;
+ detail?: string;
}
export enum BackupStates {
@@ -302,12 +304,13 @@ export interface MethodSpec {
usage_fee: string;
}
-export type AuthenticationProviderStatusEmpty = {
+export type AuthenticationProviderStatusNotContacted = {
status: "not-contacted";
};
export interface AuthenticationProviderStatusOk {
status: "ok";
+
annual_fee: string;
business_name: string;
currency: string;
@@ -320,8 +323,13 @@ export interface AuthenticationProviderStatusOk {
// FIXME: add timestamp?
}
+export interface AuthenticationProviderStatusDisabled {
+ status: "disabled";
+}
+
export interface AuthenticationProviderStatusError {
status: "error";
+
http_status?: number;
code: number;
hint?: string;
@@ -329,7 +337,8 @@ export interface AuthenticationProviderStatusError {
}
export type AuthenticationProviderStatus =
- | AuthenticationProviderStatusEmpty
+ | AuthenticationProviderStatusNotContacted
+ | AuthenticationProviderStatusDisabled
| AuthenticationProviderStatusError
| AuthenticationProviderStatusOk;
@@ -486,7 +495,6 @@ export interface PolicyMetaInfo {
secret_name?: string;
}
-
/**
* Aggregated / de-duplicated policy meta info.
*/
@@ -495,7 +503,7 @@ export interface AggregatedPolicyMetaInfo {
policy_hash: string;
attribute_mask: number;
providers: {
- provider_url: string;
+ url: string;
version: number;
}[];
}
diff --git a/packages/anastasis-webui/src/pages/home/AttributeEntryScreen.tsx b/packages/anastasis-webui/src/pages/home/AttributeEntryScreen.tsx
index c14365d24..501415c40 100644
--- a/packages/anastasis-webui/src/pages/home/AttributeEntryScreen.tsx
+++ b/packages/anastasis-webui/src/pages/home/AttributeEntryScreen.tsx
@@ -19,7 +19,7 @@ export function AttributeEntryScreen(): VNode {
const [attrs, setAttrs] = useState<Record<string, string>>(
currentIdentityAttributes,
);
- const isBackup = state && state.backup_state;
+ const isBackup = state?.reducer_type === "backup";
const [askUserIfSure, setAskUserIfSure] = useState(false);
if (!reducer) {
diff --git a/packages/anastasis-webui/src/pages/home/AuthenticationEditorScreen.tsx b/packages/anastasis-webui/src/pages/home/AuthenticationEditorScreen.tsx
index 17987796f..f0cf9b88c 100644
--- a/packages/anastasis-webui/src/pages/home/AuthenticationEditorScreen.tsx
+++ b/packages/anastasis-webui/src/pages/home/AuthenticationEditorScreen.tsx
@@ -30,10 +30,7 @@ export function AuthenticationEditorScreen(): VNode {
if (!reducer) {
return <div>no reducer in context</div>;
}
- if (
- !reducer.currentReducerState ||
- reducer.currentReducerState.backup_state === undefined
- ) {
+ if (reducer.currentReducerState?.reducer_type !== "backup") {
return <div>invalid state</div>;
}
const configuredAuthMethods: AuthMethod[] =
@@ -62,7 +59,7 @@ export function AuthenticationEditorScreen(): VNode {
const authAvailableSet = new Set<string>();
for (const provKey of Object.keys(providers)) {
const p = providers[provKey];
- if ("http_status" in p && !("error_code" in p) && p.methods) {
+ if (p.status === "ok") {
for (const meth of p.methods) {
authAvailableSet.add(meth.type);
}
diff --git a/packages/anastasis-webui/src/pages/home/BackupFinishedScreen.tsx b/packages/anastasis-webui/src/pages/home/BackupFinishedScreen.tsx
index d6272d843..cbdfcdce7 100644
--- a/packages/anastasis-webui/src/pages/home/BackupFinishedScreen.tsx
+++ b/packages/anastasis-webui/src/pages/home/BackupFinishedScreen.tsx
@@ -9,10 +9,7 @@ export function BackupFinishedScreen(): VNode {
if (!reducer) {
return <div>no reducer in context</div>;
}
- if (
- !reducer.currentReducerState ||
- reducer.currentReducerState.backup_state === undefined
- ) {
+ if (reducer.currentReducerState?.reducer_type !== "backup") {
return <div>invalid state</div>;
}
const details = reducer.currentReducerState.success_details;
diff --git a/packages/anastasis-webui/src/pages/home/ChallengeOverviewScreen.tsx b/packages/anastasis-webui/src/pages/home/ChallengeOverviewScreen.tsx
index f24478d19..11001194a 100644
--- a/packages/anastasis-webui/src/pages/home/ChallengeOverviewScreen.tsx
+++ b/packages/anastasis-webui/src/pages/home/ChallengeOverviewScreen.tsx
@@ -55,10 +55,7 @@ export function ChallengeOverviewScreen(): VNode {
if (!reducer) {
return <div>no reducer in context</div>;
}
- if (
- !reducer.currentReducerState ||
- reducer.currentReducerState.recovery_state === undefined
- ) {
+ if (reducer.currentReducerState?.reducer_type !== "recovery") {
return <div>invalid state</div>;
}
diff --git a/packages/anastasis-webui/src/pages/home/ChallengePayingScreen.tsx b/packages/anastasis-webui/src/pages/home/ChallengePayingScreen.tsx
index ffcc8fafc..2e14f44cf 100644
--- a/packages/anastasis-webui/src/pages/home/ChallengePayingScreen.tsx
+++ b/packages/anastasis-webui/src/pages/home/ChallengePayingScreen.tsx
@@ -7,10 +7,7 @@ export function ChallengePayingScreen(): VNode {
if (!reducer) {
return <div>no reducer in context</div>;
}
- if (
- !reducer.currentReducerState ||
- reducer.currentReducerState.recovery_state === undefined
- ) {
+ if (reducer.currentReducerState?.reducer_type !== "recovery") {
return <div>invalid state</div>;
}
const payments = [""]; //reducer.currentReducerState.payments ??
diff --git a/packages/anastasis-webui/src/pages/home/EditPoliciesScreen.tsx b/packages/anastasis-webui/src/pages/home/EditPoliciesScreen.tsx
index 4e0dc2906..a57f7b08b 100644
--- a/packages/anastasis-webui/src/pages/home/EditPoliciesScreen.tsx
+++ b/packages/anastasis-webui/src/pages/home/EditPoliciesScreen.tsx
@@ -38,10 +38,7 @@ export function EditPoliciesScreen({
if (!reducer) {
return <div>no reducer in context</div>;
}
- if (
- !reducer.currentReducerState ||
- reducer.currentReducerState.backup_state === undefined
- ) {
+ if (reducer.currentReducerState?.reducer_type !== "backup") {
return <div>invalid state</div>;
}
diff --git a/packages/anastasis-webui/src/pages/home/PoliciesPayingScreen.tsx b/packages/anastasis-webui/src/pages/home/PoliciesPayingScreen.tsx
index c3568b32d..2b2096dab 100644
--- a/packages/anastasis-webui/src/pages/home/PoliciesPayingScreen.tsx
+++ b/packages/anastasis-webui/src/pages/home/PoliciesPayingScreen.tsx
@@ -7,10 +7,7 @@ export function PoliciesPayingScreen(): VNode {
if (!reducer) {
return <div>no reducer in context</div>;
}
- if (
- !reducer.currentReducerState ||
- reducer.currentReducerState.backup_state === undefined
- ) {
+ if (reducer.currentReducerState?.reducer_type !== "backup") {
return <div>invalid state</div>;
}
const payments = reducer.currentReducerState.policy_payment_requests ?? [];
diff --git a/packages/anastasis-webui/src/pages/home/RecoveryFinishedScreen.tsx b/packages/anastasis-webui/src/pages/home/RecoveryFinishedScreen.tsx
index d83482559..326a9a59d 100644
--- a/packages/anastasis-webui/src/pages/home/RecoveryFinishedScreen.tsx
+++ b/packages/anastasis-webui/src/pages/home/RecoveryFinishedScreen.tsx
@@ -18,10 +18,7 @@ export function RecoveryFinishedScreen(): VNode {
if (!reducer) {
return <div>no reducer in context</div>;
}
- if (
- !reducer.currentReducerState ||
- reducer.currentReducerState.recovery_state === undefined
- ) {
+ if (reducer.currentReducerState?.reducer_type !== "recovery") {
return <div>invalid state</div>;
}
const secretName = reducer.currentReducerState.recovery_document?.secret_name;
diff --git a/packages/anastasis-webui/src/pages/home/ReviewPoliciesScreen.tsx b/packages/anastasis-webui/src/pages/home/ReviewPoliciesScreen.tsx
index 4253f4617..5d75d5aaa 100644
--- a/packages/anastasis-webui/src/pages/home/ReviewPoliciesScreen.tsx
+++ b/packages/anastasis-webui/src/pages/home/ReviewPoliciesScreen.tsx
@@ -15,10 +15,7 @@ export function ReviewPoliciesScreen(): VNode {
if (!reducer) {
return <div>no reducer in context</div>;
}
- if (
- !reducer.currentReducerState ||
- reducer.currentReducerState.backup_state === undefined
- ) {
+ if (reducer.currentReducerState?.reducer_type !== "backup") {
return <div>invalid state</div>;
}
diff --git a/packages/anastasis-webui/src/pages/home/SecretEditorScreen.tsx b/packages/anastasis-webui/src/pages/home/SecretEditorScreen.tsx
index d9bf084ab..0931f4069 100644
--- a/packages/anastasis-webui/src/pages/home/SecretEditorScreen.tsx
+++ b/packages/anastasis-webui/src/pages/home/SecretEditorScreen.tsx
@@ -27,10 +27,7 @@ export function SecretEditorScreen(): VNode {
if (!reducer) {
return <div>no reducer in context</div>;
}
- if (
- !reducer.currentReducerState ||
- reducer.currentReducerState.backup_state === undefined
- ) {
+ if (reducer.currentReducerState?.reducer_type !== "backup") {
return <div>invalid state</div>;
}
diff --git a/packages/anastasis-webui/src/pages/home/SecretSelectionScreen.tsx b/packages/anastasis-webui/src/pages/home/SecretSelectionScreen.tsx
index 84f0303fe..45d8e46f3 100644
--- a/packages/anastasis-webui/src/pages/home/SecretSelectionScreen.tsx
+++ b/packages/anastasis-webui/src/pages/home/SecretSelectionScreen.tsx
@@ -31,7 +31,7 @@ export function SecretSelectionScreen(): VNode {
if (
!reducer.currentReducerState ||
- reducer.currentReducerState.recovery_state === undefined
+ reducer.currentReducerState.reducer_type !== "recovery"
) {
return <div>invalid state</div>;
}
@@ -73,14 +73,17 @@ export function SecretSelectionScreen(): VNode {
}
return (
- <AnastasisClientFrame title="Recovery: Select secret" hideNext="Please select version to recover">
+ <AnastasisClientFrame
+ title="Recovery: Select secret"
+ hideNext="Please select version to recover"
+ >
<p>Found versions:</p>
{policies.map((x) => (
<div>
{x.policy_hash} / {x.secret_name}
<button
onClick={async () => {
- await reducer.transition("change_version", {
+ await reducer.transition("select_version", {
selection: x,
});
}}
@@ -119,7 +122,7 @@ export function OldSecretSelectionScreen(): VNode {
}
if (
!reducer.currentReducerState ||
- reducer.currentReducerState.recovery_state === undefined
+ reducer.currentReducerState.reducer_type !== "recovery"
) {
return <div>invalid state</div>;
}
@@ -127,7 +130,7 @@ export function OldSecretSelectionScreen(): VNode {
async function doSelectVersion(p: string, n: number): Promise<void> {
if (!reducer) return Promise.resolve();
return reducer.runTransaction(async (tx) => {
- await tx.transition("change_version", {
+ await tx.transition("select_version", {
version: n,
provider_url: p,
});
diff --git a/packages/anastasis-webui/src/pages/home/SolveScreen.tsx b/packages/anastasis-webui/src/pages/home/SolveScreen.tsx
index c695b9b22..1070cf8a9 100644
--- a/packages/anastasis-webui/src/pages/home/SolveScreen.tsx
+++ b/packages/anastasis-webui/src/pages/home/SolveScreen.tsx
@@ -135,10 +135,7 @@ export function SolveScreen(): VNode {
</AnastasisClientFrame>
);
}
- if (
- !reducer.currentReducerState ||
- reducer.currentReducerState.recovery_state === undefined
- ) {
+ if (reducer.currentReducerState?.reducer_type !== "recovery") {
return (
<AnastasisClientFrame hideNav title="Recovery problem">
<div>invalid state</div>
diff --git a/packages/anastasis-webui/src/pages/home/TruthsPayingScreen.tsx b/packages/anastasis-webui/src/pages/home/TruthsPayingScreen.tsx
index 6f95fa93b..c6f8cbead 100644
--- a/packages/anastasis-webui/src/pages/home/TruthsPayingScreen.tsx
+++ b/packages/anastasis-webui/src/pages/home/TruthsPayingScreen.tsx
@@ -7,10 +7,7 @@ export function TruthsPayingScreen(): VNode {
if (!reducer) {
return <div>no reducer in context</div>;
}
- if (
- !reducer.currentReducerState ||
- reducer.currentReducerState.backup_state === undefined
- ) {
+ if (reducer.currentReducerState?.reducer_type !== "backup") {
return <div>invalid state</div>;
}
const payments = reducer.currentReducerState.payments ?? [];