validate wire fees and acct info
This commit is contained in:
parent
8115ac660c
commit
7b54439fd6
@ -409,6 +409,10 @@ export class CryptoApi {
|
|||||||
return this.doRpc<boolean>("rsaVerify", 4, hm, sig, pk);
|
return this.doRpc<boolean>("rsaVerify", 4, hm, sig, pk);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isValidWireAccount(paytoUri: string, sig: string, masterPub: string): Promise<boolean> {
|
||||||
|
return this.doRpc<boolean>("isValidWireAccount", 4, paytoUri, sig, masterPub);
|
||||||
|
}
|
||||||
|
|
||||||
createPaybackRequest(coin: CoinRecord): Promise<PaybackRequest> {
|
createPaybackRequest(coin: CoinRecord): Promise<PaybackRequest> {
|
||||||
return this.doRpc<PaybackRequest>("createPaybackRequest", 1, coin);
|
return this.doRpc<PaybackRequest>("createPaybackRequest", 1, coin);
|
||||||
}
|
}
|
||||||
|
@ -68,15 +68,17 @@ import {
|
|||||||
rsaVerify,
|
rsaVerify,
|
||||||
} from "../talerCrypto";
|
} from "../talerCrypto";
|
||||||
import { randomBytes } from "../primitives/nacl-fast";
|
import { randomBytes } from "../primitives/nacl-fast";
|
||||||
|
import { kdf } from "../primitives/kdf";
|
||||||
|
|
||||||
enum SignaturePurpose {
|
enum SignaturePurpose {
|
||||||
RESERVE_WITHDRAW = 1200,
|
RESERVE_WITHDRAW = 1200,
|
||||||
WALLET_COIN_DEPOSIT = 1201,
|
WALLET_COIN_DEPOSIT = 1201,
|
||||||
MASTER_DENOMINATION_KEY_VALIDITY = 1025,
|
MASTER_DENOMINATION_KEY_VALIDITY = 1025,
|
||||||
|
MASTER_WIRE_FEES = 1028,
|
||||||
|
MASTER_WIRE_DETAILS = 1030,
|
||||||
WALLET_COIN_MELT = 1202,
|
WALLET_COIN_MELT = 1202,
|
||||||
TEST = 4242,
|
TEST = 4242,
|
||||||
MERCHANT_PAYMENT_OK = 1104,
|
MERCHANT_PAYMENT_OK = 1104,
|
||||||
MASTER_WIRE_FEES = 1028,
|
|
||||||
WALLET_COIN_PAYBACK = 1203,
|
WALLET_COIN_PAYBACK = 1203,
|
||||||
WALLET_COIN_LINK = 1204,
|
WALLET_COIN_LINK = 1204,
|
||||||
}
|
}
|
||||||
@ -157,9 +159,7 @@ export class CryptoImplementation {
|
|||||||
* Create a pre-coin of the given denomination to be withdrawn from then given
|
* Create a pre-coin of the given denomination to be withdrawn from then given
|
||||||
* reserve.
|
* reserve.
|
||||||
*/
|
*/
|
||||||
createPlanchet(
|
createPlanchet(req: PlanchetCreationRequest): PlanchetCreationResult {
|
||||||
req: PlanchetCreationRequest,
|
|
||||||
): PlanchetCreationResult {
|
|
||||||
const reservePub = decodeCrock(req.reservePub);
|
const reservePub = decodeCrock(req.reservePub);
|
||||||
const reservePriv = decodeCrock(req.reservePriv);
|
const reservePriv = decodeCrock(req.reservePriv);
|
||||||
const denomPub = decodeCrock(req.denomPub);
|
const denomPub = decodeCrock(req.denomPub);
|
||||||
@ -264,6 +264,7 @@ export class CryptoImplementation {
|
|||||||
.put(timestampToBuffer(wf.startStamp))
|
.put(timestampToBuffer(wf.startStamp))
|
||||||
.put(timestampToBuffer(wf.endStamp))
|
.put(timestampToBuffer(wf.endStamp))
|
||||||
.put(amountToBuffer(wf.wireFee))
|
.put(amountToBuffer(wf.wireFee))
|
||||||
|
.put(amountToBuffer(wf.closingFee))
|
||||||
.build();
|
.build();
|
||||||
const sig = decodeCrock(wf.sig);
|
const sig = decodeCrock(wf.sig);
|
||||||
const pub = decodeCrock(masterPub);
|
const pub = decodeCrock(masterPub);
|
||||||
@ -292,6 +293,23 @@ export class CryptoImplementation {
|
|||||||
return eddsaVerify(p, sig, pub);
|
return eddsaVerify(p, sig, pub);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isValidWireAccount(
|
||||||
|
paytoUri: string,
|
||||||
|
sig: string,
|
||||||
|
masterPub: string,
|
||||||
|
): boolean {
|
||||||
|
const h = kdf(
|
||||||
|
64,
|
||||||
|
stringToBytes("exchange-wire-signature"),
|
||||||
|
stringToBytes(paytoUri + "\0"),
|
||||||
|
new Uint8Array(0),
|
||||||
|
);
|
||||||
|
const p = buildSigPS(SignaturePurpose.MASTER_WIRE_DETAILS)
|
||||||
|
.put(h)
|
||||||
|
.build();
|
||||||
|
return eddsaVerify(p, decodeCrock(sig), decodeCrock(masterPub));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new EdDSA key pair.
|
* Create a new EdDSA key pair.
|
||||||
*/
|
*/
|
||||||
|
@ -15,10 +15,13 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { InternalWalletState } from "./state";
|
import { InternalWalletState } from "./state";
|
||||||
|
import { WALLET_CACHE_BREAKER_CLIENT_VERSION } from "../wallet";
|
||||||
import {
|
import {
|
||||||
WALLET_CACHE_BREAKER_CLIENT_VERSION,
|
KeysJson,
|
||||||
} from "../wallet";
|
Denomination,
|
||||||
import { KeysJson, Denomination, ExchangeWireJson } from "../talerTypes";
|
ExchangeWireJson,
|
||||||
|
WireFeesJson,
|
||||||
|
} from "../talerTypes";
|
||||||
import { getTimestampNow, OperationError } from "../walletTypes";
|
import { getTimestampNow, OperationError } from "../walletTypes";
|
||||||
import {
|
import {
|
||||||
ExchangeRecord,
|
ExchangeRecord,
|
||||||
@ -229,8 +232,12 @@ async function updateExchangeWithWireInfo(
|
|||||||
if (exchange.updateStatus != ExchangeUpdateStatus.FETCH_WIRE) {
|
if (exchange.updateStatus != ExchangeUpdateStatus.FETCH_WIRE) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const details = exchange.details;
|
||||||
|
if (!details) {
|
||||||
|
throw Error("invalid exchange state");
|
||||||
|
}
|
||||||
const reqUrl = new URL("wire", exchangeBaseUrl);
|
const reqUrl = new URL("wire", exchangeBaseUrl);
|
||||||
reqUrl.searchParams.set("cacheBreaker", WALLET_CACHE_BREAKER_CLIENT_VERSION)
|
reqUrl.searchParams.set("cacheBreaker", WALLET_CACHE_BREAKER_CLIENT_VERSION);
|
||||||
|
|
||||||
const resp = await ws.http.get(reqUrl.href);
|
const resp = await ws.http.get(reqUrl.href);
|
||||||
|
|
||||||
@ -239,6 +246,17 @@ async function updateExchangeWithWireInfo(
|
|||||||
throw Error("/wire response malformed");
|
throw Error("/wire response malformed");
|
||||||
}
|
}
|
||||||
const wireInfo = ExchangeWireJson.checked(wiJson);
|
const wireInfo = ExchangeWireJson.checked(wiJson);
|
||||||
|
for (const a of wireInfo.accounts) {
|
||||||
|
console.log("validating exchange acct");
|
||||||
|
const isValid = await ws.cryptoApi.isValidWireAccount(
|
||||||
|
a.url,
|
||||||
|
a.master_sig,
|
||||||
|
details.masterPublicKey,
|
||||||
|
);
|
||||||
|
if (!isValid) {
|
||||||
|
throw Error("exchange acct signature invalid");
|
||||||
|
}
|
||||||
|
}
|
||||||
const feesForType: { [wireMethod: string]: WireFee[] } = {};
|
const feesForType: { [wireMethod: string]: WireFee[] } = {};
|
||||||
for (const wireMethod of Object.keys(wireInfo.fees)) {
|
for (const wireMethod of Object.keys(wireInfo.fees)) {
|
||||||
const feeList: WireFee[] = [];
|
const feeList: WireFee[] = [];
|
||||||
@ -251,13 +269,22 @@ async function updateExchangeWithWireInfo(
|
|||||||
if (!endStamp) {
|
if (!endStamp) {
|
||||||
throw Error("wrong date format");
|
throw Error("wrong date format");
|
||||||
}
|
}
|
||||||
feeList.push({
|
const fee: WireFee = {
|
||||||
closingFee: Amounts.parseOrThrow(x.closing_fee),
|
closingFee: Amounts.parseOrThrow(x.closing_fee),
|
||||||
endStamp,
|
endStamp,
|
||||||
sig: x.sig,
|
sig: x.sig,
|
||||||
startStamp,
|
startStamp,
|
||||||
wireFee: Amounts.parseOrThrow(x.wire_fee),
|
wireFee: Amounts.parseOrThrow(x.wire_fee),
|
||||||
});
|
};
|
||||||
|
const isValid = await ws.cryptoApi.isValidWireFee(
|
||||||
|
wireMethod,
|
||||||
|
fee,
|
||||||
|
details.masterPublicKey,
|
||||||
|
);
|
||||||
|
if (!isValid) {
|
||||||
|
throw Error("exchange wire fee signature invalid");
|
||||||
|
}
|
||||||
|
feeList.push(fee);
|
||||||
}
|
}
|
||||||
feesForType[wireMethod] = feeList;
|
feesForType[wireMethod] = feeList;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user