anastasis-core: support poll transition

This commit is contained in:
Florian Dold 2021-11-05 16:07:57 +01:00
parent 4a8e4b9026
commit 842cc32754
No known key found for this signature in database
GPG Key ID: D2E4F00F29D02A4B
4 changed files with 87 additions and 3 deletions

View File

@ -80,6 +80,25 @@ export interface ChallengeFeedbackAuthIban {
* be contained in the bank transfer.
*/
wire_transfer_subject: string;
/**
* FIXME: This field is only present for compatibility with
* the C reducer test suite.
*/
method: "iban";
answer_code: number;
/**
* FIXME: This field is only present for compatibility with
* the C reducer test suite.
*/
details: {
challenge_amount: AmountString;
credit_iban: string;
business_name: string;
wire_transfer_subject: string;
};
}
/**

View File

@ -25,6 +25,7 @@ import {
import { anastasisData } from "./anastasis-data.js";
import {
EscrowConfigurationResponse,
IbanExternalAuthResponse,
TruthUploadRequest,
} from "./provider-types.js";
import {
@ -809,6 +810,39 @@ async function tryRecoverSecret(
return { ...state };
}
/**
* Re-check the status of challenges that are solved asynchronously.
*/
async function pollChallenges(
state: ReducerStateRecovery,
args: void,
): Promise<ReducerStateRecovery | ReducerStateError> {
for (const truthUuid in state.challenge_feedback) {
if (state.recovery_state === RecoveryStates.RecoveryFinished) {
break;
}
const feedback = state.challenge_feedback[truthUuid];
const truth = state.verbatim_recovery_document!.escrow_methods.find(
(x) => x.uuid === truthUuid,
);
if (!truth) {
logger.warn(
"truth for challenge feedback entry not found in recovery document",
);
continue;
}
if (feedback.state === ChallengeFeedbackStatus.AuthIban) {
const s2 = await requestTruth(state, truth, {
pin: feedback.answer_code,
});
if (s2.recovery_state) {
state = s2;
}
}
}
return state;
}
/**
* Request a truth, optionally with a challenge solution
* provided by the user.
@ -839,6 +873,7 @@ async function requestTruth(
case ChallengeType.Email:
case ChallengeType.Sms:
case ChallengeType.Post:
case ChallengeType.Iban:
case ChallengeType.Totp: {
if ("answer" in solveRequest) {
const s = solveRequest.answer.trim().replace(/^A-/, "");
@ -857,7 +892,7 @@ async function requestTruth(
break;
}
default:
throw Error("unsupported challenge type");
throw Error(`unsupported challenge type "${truth.escrow_type}""`);
}
url.searchParams.set("response", respHash);
}
@ -934,7 +969,24 @@ async function requestTruth(
const body = await resp.json();
logger.info(`got body ${j2s(body)}`);
if (body.method === "iban") {
// FIXME:
const b = body as IbanExternalAuthResponse;
return {
...state,
recovery_state: RecoveryStates.ChallengeSolving,
challenge_feedback: {
...state.challenge_feedback,
[truth.uuid]: {
state: ChallengeFeedbackStatus.AuthIban,
answer_code: b.answer_code,
business_name: b.details.business_name,
challenge_amount: b.details.challenge_amount,
credit_iban: b.details.credit_iban,
wire_transfer_subject: b.details.wire_transfer_subject,
details: b.details,
method: "iban",
},
},
};
} else {
return {
code: TalerErrorCode.ANASTASIS_TRUTH_CHALLENGE_FAILED,
@ -1395,6 +1447,7 @@ const recoveryTransitions: Record<
codecForActionArgsSelectChallenge(),
selectChallenge,
),
...transition("poll", codecForAny(), pollChallenges),
...transition("next", codecForAny(), nextFromChallengeSelecting),
},
[RecoveryStates.ChallengeSolving]: {

View File

@ -1,4 +1,4 @@
import { AmountString } from "@gnu-taler/taler-util";
import { Amounts, AmountString } from "@gnu-taler/taler-util";
export interface EscrowConfigurationResponse {
// Protocol identifier, clarifies that this is an Anastasis provider.
@ -72,3 +72,14 @@ export interface TruthUploadRequest {
// store the truth?
storage_duration_years: number;
}
export interface IbanExternalAuthResponse {
method: "iban";
answer_code: number;
details: {
challenge_amount: AmountString;
credit_iban: string;
business_name: string;
wire_transfer_subject: string;
};
}

View File

@ -6,6 +6,7 @@ import {
codecForNumber,
codecForString,
codecForTimestamp,
Duration,
Timestamp,
} from "@gnu-taler/taler-util";
import { ChallengeFeedback } from "./challenge-feedback-types.js";