anastasis: make iban auth work again

This commit is contained in:
Florian Dold 2022-04-14 14:14:02 +02:00
parent aad836ee90
commit bc05050524
No known key found for this signature in database
GPG Key ID: D2E4F00F29D02A4B
9 changed files with 92 additions and 51 deletions

View File

@ -28,7 +28,7 @@ export enum ChallengeFeedbackStatus {
TalerPayment = "taler-payment", TalerPayment = "taler-payment",
Unsupported = "unsupported", Unsupported = "unsupported",
RateLimitExceeded = "rate-limit-exceeded", RateLimitExceeded = "rate-limit-exceeded",
AuthIban = "auth-iban", IbanInstructions = "iban-instructions",
IncorrectAnswer = "incorrect-answer", IncorrectAnswer = "incorrect-answer",
} }
@ -93,7 +93,7 @@ export interface ChallengeFeedbackRateLimitExceeded {
* IBAN bank transfer. * IBAN bank transfer.
*/ */
export interface ChallengeFeedbackBankTransferRequired { export interface ChallengeFeedbackBankTransferRequired {
state: ChallengeFeedbackStatus.AuthIban; state: ChallengeFeedbackStatus.IbanInstructions;
/** /**
* Amount that should be transfered for a successful authentication. * Amount that should be transfered for a successful authentication.

View File

@ -1,3 +1,22 @@
/*
This file is part of GNU Anastasis
(C) 2021-2022 Anastasis SARL
GNU Anastasis is free software; you can redistribute it and/or modify it under the
terms of the GNU Affero General Public License as published by the Free Software
Foundation; either version 3, or (at your option) any later version.
GNU Anastasis is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
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/>
*/
/**
* Imports.
*/
import { import {
AmountJson, AmountJson,
AmountLike, AmountLike,
@ -22,6 +41,7 @@ import {
TalerSignaturePurpose, TalerSignaturePurpose,
AbsoluteTime, AbsoluteTime,
URL, URL,
j2s,
} from "@gnu-taler/taler-util"; } from "@gnu-taler/taler-util";
import { anastasisData } from "./anastasis-data.js"; import { anastasisData } from "./anastasis-data.js";
import { import {
@ -879,7 +899,7 @@ async function pollChallenges(
); );
continue; continue;
} }
if (feedback.state === ChallengeFeedbackStatus.AuthIban) { if (feedback.state === ChallengeFeedbackStatus.IbanInstructions) {
const s2 = await requestTruth(state, truth, { const s2 = await requestTruth(state, truth, {
pin: feedback.answer_code, pin: feedback.answer_code,
}); });
@ -1080,7 +1100,7 @@ async function changeVersion(
): Promise<ReducerStateRecovery | ReducerStateError> { ): Promise<ReducerStateRecovery | ReducerStateError> {
const st: ReducerStateRecovery = { const st: ReducerStateRecovery = {
...state, ...state,
selected_version: args.selection, selected_version: args,
}; };
return downloadPolicy(st); return downloadPolicy(st);
} }
@ -1147,9 +1167,10 @@ async function selectChallenge(
if (resp.status === HttpStatusCode.Ok) { if (resp.status === HttpStatusCode.Ok) {
const respBodyJson = await resp.json(); const respBodyJson = await resp.json();
logger.info(`validating ${j2s(respBodyJson)}`);
const instr = codecForChallengeInstructionMessage().decode(respBodyJson); const instr = codecForChallengeInstructionMessage().decode(respBodyJson);
let feedback: ChallengeFeedback; let feedback: ChallengeFeedback;
switch (instr.method) { switch (instr.challenge_type) {
case "FILE_WRITTEN": { case "FILE_WRITTEN": {
feedback = { feedback = {
state: ChallengeFeedbackStatus.CodeInFile, state: ChallengeFeedbackStatus.CodeInFile,
@ -1160,12 +1181,12 @@ async function selectChallenge(
} }
case "IBAN_WIRE": { case "IBAN_WIRE": {
feedback = { feedback = {
state: ChallengeFeedbackStatus.AuthIban, state: ChallengeFeedbackStatus.IbanInstructions,
answer_code: instr.answer_code, answer_code: instr.wire_details.answer_code,
target_business_name: instr.business_name, target_business_name: instr.wire_details.business_name,
challenge_amount: instr.amount, challenge_amount: instr.wire_details.challenge_amount,
target_iban: instr.credit_iban, target_iban: instr.wire_details.credit_iban,
wire_transfer_subject: instr.wire_transfer_subject, wire_transfer_subject: instr.wire_details.wire_transfer_subject,
}; };
break; break;
} }

View File

@ -20,6 +20,7 @@ import {
buildCodecForUnion, buildCodecForUnion,
Codec, Codec,
codecForAmountString, codecForAmountString,
codecForAny,
codecForConstString, codecForConstString,
codecForNumber, codecForNumber,
codecForString, codecForString,
@ -137,32 +138,34 @@ export type ChallengeInstructionMessage =
export interface IbanChallengeInstructionMessage { export interface IbanChallengeInstructionMessage {
// What kind of challenge is this? // What kind of challenge is this?
method: "IBAN_WIRE"; challenge_type: "IBAN_WIRE";
// How much should be wired? wire_details: {
amount: AmountString; // How much should be wired?
challenge_amount: AmountString;
// What is the target IBAN? // What is the target IBAN?
credit_iban: string; credit_iban: string;
// What is the receiver name? // What is the receiver name?
business_name: string; business_name: string;
// What is the expected wire transfer subject? // What is the expected wire transfer subject?
wire_transfer_subject: string; wire_transfer_subject: string;
// What is the numeric code (also part of the // What is the numeric code (also part of the
// wire transfer subject) to be hashed when // wire transfer subject) to be hashed when
// solving the challenge? // solving the challenge?
answer_code: number; answer_code: number;
// Hint about the origin account that must be used. // Hint about the origin account that must be used.
debit_account_hint: string; debit_account_hint: string;
};
} }
export interface PinChallengeInstructionMessage { export interface PinChallengeInstructionMessage {
// What kind of challenge is this? // What kind of challenge is this?
method: "TAN_SENT"; challenge_type: "TAN_SENT";
// Where was the PIN code sent? Note that this // Where was the PIN code sent? Note that this
// address will most likely have been obscured // address will most likely have been obscured
@ -172,7 +175,7 @@ export interface PinChallengeInstructionMessage {
export interface FileChallengeInstructionMessage { export interface FileChallengeInstructionMessage {
// What kind of challenge is this? // What kind of challenge is this?
method: "FILE_WRITTEN"; challenge_type: "FILE_WRITTEN";
// Name of the file where the PIN code was written. // Name of the file where the PIN code was written.
filename: string; filename: string;
@ -181,33 +184,28 @@ export interface FileChallengeInstructionMessage {
export const codecForFileChallengeInstructionMessage = export const codecForFileChallengeInstructionMessage =
(): Codec<FileChallengeInstructionMessage> => (): Codec<FileChallengeInstructionMessage> =>
buildCodecForObject<FileChallengeInstructionMessage>() buildCodecForObject<FileChallengeInstructionMessage>()
.property("method", codecForConstString("FILE_WRITTEN")) .property("challenge_type", codecForConstString("FILE_WRITTEN"))
.property("filename", codecForString()) .property("filename", codecForString())
.build("FileChallengeInstructionMessage"); .build("FileChallengeInstructionMessage");
export const codecForPinChallengeInstructionMessage = export const codecForPinChallengeInstructionMessage =
(): Codec<PinChallengeInstructionMessage> => (): Codec<PinChallengeInstructionMessage> =>
buildCodecForObject<PinChallengeInstructionMessage>() buildCodecForObject<PinChallengeInstructionMessage>()
.property("method", codecForConstString("TAN_SENT")) .property("challenge_type", codecForConstString("TAN_SENT"))
.property("tan_address_hint", codecForString()) .property("tan_address_hint", codecForString())
.build("PinChallengeInstructionMessage"); .build("PinChallengeInstructionMessage");
export const codecForIbanChallengeInstructionMessage = export const codecForIbanChallengeInstructionMessage =
(): Codec<IbanChallengeInstructionMessage> => (): Codec<IbanChallengeInstructionMessage> =>
buildCodecForObject<IbanChallengeInstructionMessage>() buildCodecForObject<IbanChallengeInstructionMessage>()
.property("method", codecForConstString("IBAN_WIRE")) .property("challenge_type", codecForConstString("IBAN_WIRE"))
.property("amount", codecForAmountString()) .property("wire_details", codecForAny())
.property("business_name", codecForString())
.property("credit_iban", codecForString())
.property("wire_transfer_subject", codecForString())
.property("answer_code", codecForNumber())
.property("debit_account_hint", codecForString())
.build("IbanChallengeInstructionMessage"); .build("IbanChallengeInstructionMessage");
export const codecForChallengeInstructionMessage = export const codecForChallengeInstructionMessage =
(): Codec<ChallengeInstructionMessage> => (): Codec<ChallengeInstructionMessage> =>
buildCodecForUnion<ChallengeInstructionMessage>() buildCodecForUnion<ChallengeInstructionMessage>()
.discriminateOn("method") .discriminateOn("challenge_type")
.alternative("FILE_WRITTEN", codecForFileChallengeInstructionMessage()) .alternative("FILE_WRITTEN", codecForFileChallengeInstructionMessage())
.alternative("IBAN_WIRE", codecForIbanChallengeInstructionMessage()) .alternative("IBAN_WIRE", codecForIbanChallengeInstructionMessage())
.alternative("TAN_SENT", codecForPinChallengeInstructionMessage()) .alternative("TAN_SENT", codecForPinChallengeInstructionMessage())

View File

@ -221,7 +221,7 @@ export interface ReducerStateRecovery {
/** /**
* Explicitly selected version by the user. * Explicitly selected version by the user.
*/ */
selected_version?: AggregatedPolicyMetaInfo; selected_version?: SelectedVersionInfo;
challenge_feedback?: { [uuid: string]: ChallengeFeedback }; challenge_feedback?: { [uuid: string]: ChallengeFeedback };
@ -464,10 +464,16 @@ export interface ActionArgsUpdateExpiration {
expiration: TalerProtocolTimestamp; expiration: TalerProtocolTimestamp;
} }
export interface ActionArgsChangeVersion { export interface SelectedVersionInfo {
selection: AggregatedPolicyMetaInfo; attribute_mask: number;
providers: {
url: string;
version: number;
}[];
} }
export type ActionArgsChangeVersion = SelectedVersionInfo;
export interface ActionArgsUpdatePolicy { export interface ActionArgsUpdatePolicy {
policy_index: number; policy_index: number;
policy: PolicyMember[]; policy: PolicyMember[];
@ -518,10 +524,8 @@ export interface DiscoveryResult {
cursor?: DiscoveryCursor; cursor?: DiscoveryCursor;
} }
export const codecForActionArgsChangeVersion = () => // FIXME: specify schema!
buildCodecForObject<ActionArgsChangeVersion>() export const codecForActionArgsChangeVersion = codecForAny;
.property("selection", codecForAny())
.build("ActionArgsChangeVersion");
export const codecForPolicyMember = () => export const codecForPolicyMember = () =>
buildCodecForObject<PolicyMember>() buildCodecForObject<PolicyMember>()

View File

@ -250,7 +250,7 @@ export const OnePolicyWithAllTheChallengesInDifferentState = createExample(
challenge_feedback: { challenge_feedback: {
"uuid-1": { state: ChallengeFeedbackStatus.Solved.toString() }, "uuid-1": { state: ChallengeFeedbackStatus.Solved.toString() },
"uuid-3": { "uuid-3": {
state: ChallengeFeedbackStatus.AuthIban.toString(), state: ChallengeFeedbackStatus.IbanInstructions.toString(),
challenge_amount: "EUR:1", challenge_amount: "EUR:1",
target_iban: "DE12345789000", target_iban: "DE12345789000",
target_business_name: "Data Loss Incorporated", target_business_name: "Data Loss Incorporated",

View File

@ -16,7 +16,7 @@ function OverviewFeedbackDisplay(props: { feedback?: ChallengeFeedback }) {
switch (feedback.state) { switch (feedback.state) {
case ChallengeFeedbackStatus.Solved: case ChallengeFeedbackStatus.Solved:
return <div />; return <div />;
case ChallengeFeedbackStatus.AuthIban: case ChallengeFeedbackStatus.IbanInstructions:
return null; return null;
case ChallengeFeedbackStatus.ServerFailure: case ChallengeFeedbackStatus.ServerFailure:
return <div class="block has-text-danger">Server error.</div>; return <div class="block has-text-danger">Server error.</div>;
@ -173,7 +173,7 @@ export function ChallengeOverviewScreen(): VNode {
case ChallengeFeedbackStatus.TruthUnknown: case ChallengeFeedbackStatus.TruthUnknown:
case ChallengeFeedbackStatus.RateLimitExceeded: case ChallengeFeedbackStatus.RateLimitExceeded:
return <div />; return <div />;
case ChallengeFeedbackStatus.AuthIban: case ChallengeFeedbackStatus.IbanInstructions:
case ChallengeFeedbackStatus.TalerPayment: case ChallengeFeedbackStatus.TalerPayment:
return ( return (
<div> <div>

View File

@ -32,7 +32,7 @@ export function SolveOverviewFeedbackDisplay(props: {
]} ]}
/> />
); );
case ChallengeFeedbackStatus.AuthIban: case ChallengeFeedbackStatus.IbanInstructions:
return ( return (
<Notifications <Notifications
notifications={[ notifications={[

View File

@ -1,5 +1,23 @@
/*
This file is part of GNU Anastasis
(C) 2021-2022 Anastasis SARL
GNU Anastasis is free software; you can redistribute it and/or modify it under the
terms of the GNU Affero General Public License as published by the Free Software
Foundation; either version 3, or (at your option) any later version.
GNU Anastasis is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
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/>
*/
/**
* Imports.
*/
import { import {
ChallengeFeedbackStatus,
ChallengeInfo, ChallengeInfo,
} from "@gnu-taler/anastasis-core"; } from "@gnu-taler/anastasis-core";
import { h, VNode } from "preact"; import { h, VNode } from "preact";

View File

@ -158,7 +158,7 @@ export const TruthUnknownFeedback = createExample(TestedComponent[type].solve, {
} as ReducerState); } as ReducerState);
const ibanFeedback: ChallengeFeedbackBankTransferRequired = { const ibanFeedback: ChallengeFeedbackBankTransferRequired = {
state: ChallengeFeedbackStatus.AuthIban, state: ChallengeFeedbackStatus.IbanInstructions,
challenge_amount: "EUR:1", challenge_amount: "EUR:1",
target_iban: "DE12345789000", target_iban: "DE12345789000",
target_business_name: "Data Loss Incorporated", target_business_name: "Data Loss Incorporated",