check contract terms signature, handle errors
This commit is contained in:
parent
0d37ec5e91
commit
dffb293f2a
@ -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).
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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(
|
||||
|
@ -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.
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user