check contract terms signature, handle errors

This commit is contained in:
Florian Dold 2020-11-03 17:39:30 +01:00
parent 0d37ec5e91
commit dffb293f2a
No known key found for this signature in database
GPG Key ID: D2E4F00F29D02A4B
5 changed files with 75 additions and 1 deletions

View File

@ -3307,6 +3307,13 @@ export enum TalerErrorCode {
*/
WALLET_CONTRACT_TERMS_BASE_URL_MISMATCH = 7018,
/**
* The merchant's signature on the contract terms is invalid.
* Returned with an HTTP status code of #MHD_HTTP_UNINITIALIZED (0).
* (A value of 0 indicates that the error is generated client-side).
*/
WALLET_CONTRACT_TERMS_SIGNATURE_INVALID = 7019,
/**
* my comment
* Returned with an HTTP status code of #MHD_HTTP_INTERNAL_SERVER_ERROR (500).

View File

@ -398,6 +398,20 @@ export class CryptoApi {
);
}
isValidContractTermsSignature(
contractTermsHash: string,
sig: string,
merchantPub: string,
): Promise<boolean> {
return this.doRpc<boolean>(
"isValidContractTermsSignature",
4,
contractTermsHash,
sig,
merchantPub,
);
}
createRecoupRequest(coin: CoinRecord): Promise<RecoupRequest> {
return this.doRpc<RecoupRequest>("createRecoupRequest", 1, coin);
}

View File

@ -80,6 +80,7 @@ enum SignaturePurpose {
WALLET_COIN_MELT = 1202,
TEST = 4242,
MERCHANT_PAYMENT_OK = 1104,
MERCHANT_CONTRACT = 1101,
WALLET_COIN_RECOUP = 1203,
WALLET_COIN_LINK = 1204,
EXCHANGE_CONFIRM_RECOUP = 1039,
@ -297,6 +298,18 @@ export class CryptoImplementation {
return eddsaVerify(p, decodeCrock(sig), decodeCrock(masterPub));
}
isValidContractTermsSignature(
contractTermsHash: string,
sig: string,
merchantPub: string,
): boolean {
const cthDec = decodeCrock(contractTermsHash);
const p = buildSigPS(SignaturePurpose.MERCHANT_CONTRACT)
.put(cthDec)
.build();
return eddsaVerify(p, decodeCrock(sig), decodeCrock(merchantPub));
}
/**
* Create a new EdDSA key pair.
*/

View File

@ -58,6 +58,7 @@ import { Logger } from "../util/logging";
import { parsePayUri } from "../util/taleruri";
import {
guardOperationException,
makeErrorDetails,
OperationFailedAndReportedError,
OperationFailedError,
} from "./errors";
@ -582,6 +583,19 @@ async function resetDownloadProposalRetry(
});
}
async function failProposalPermanently(
ws: InternalWalletState,
proposalId: string,
err: TalerErrorDetails,
): Promise<void> {
await ws.db.mutate(Stores.proposals, proposalId, (x) => {
x.retryInfo.active = false;
x.lastError = err;
x.proposalStatus = ProposalStatus.PERMANENTLY_FAILED;
return x;
});
}
function getProposalRequestTimeout(proposal: ProposalRecord): Duration {
return durationMax(
{ d_ms: 60000 },
@ -663,13 +677,33 @@ async function processDownloadProposalImpl(
const parsedContractTerms = codecForContractTerms().decode(
proposalResp.contract_terms,
);
const sigValid = await ws.cryptoApi.isValidContractTermsSignature(
contractTermsHash,
proposalResp.sig,
parsedContractTerms.merchant_pub,
);
if (!sigValid) {
const err = makeErrorDetails(
TalerErrorCode.WALLET_CONTRACT_TERMS_SIGNATURE_INVALID,
"merchant's signature on contract terms is invalid",
{
merchantPub: parsedContractTerms.merchant_pub,
orderId: parsedContractTerms.order_id,
},
);
await failProposalPermanently(ws, proposalId, err);
throw new OperationFailedAndReportedError(err);
}
const fulfillmentUrl = parsedContractTerms.fulfillment_url;
const baseUrlForDownload = proposal.merchantBaseUrl;
const baseUrlFromContractTerms = parsedContractTerms.merchant_base_url;
if (baseUrlForDownload !== baseUrlFromContractTerms) {
throw OperationFailedAndReportedError.fromCode(
const err = makeErrorDetails(
TalerErrorCode.WALLET_CONTRACT_TERMS_BASE_URL_MISMATCH,
"merchant base URL mismatch",
{
@ -677,6 +711,8 @@ async function processDownloadProposalImpl(
baseUrlFromContractTerms,
},
);
await failProposalPermanently(ws, proposalId, err);
throw new OperationFailedAndReportedError(err);
}
await ws.db.runWithWriteTransaction(

View File

@ -813,6 +813,10 @@ export enum ProposalStatus {
* The user has rejected the proposal.
*/
REFUSED = "refused",
/**
* Downloading or processing the proposal has failed permanently.
*/
PERMANENTLY_FAILED = "permanently-failed",
/**
* Downloaded proposal was detected as a re-purchase.
*/