address protocol changes in the exchange

The exchange now has a wad fee and truncates the payto hash in signatures
This commit is contained in:
Florian Dold 2022-03-07 12:09:38 +01:00
parent 2cfefa9392
commit 0290c5fd37
No known key found for this signature in database
GPG Key ID: D2E4F00F29D02A4B
9 changed files with 38 additions and 10 deletions

View File

@ -1023,6 +1023,8 @@ export interface BackupExchangeWireFee {
*/ */
wire_fee: string; wire_fee: string;
wad_fee: string;
/** /**
* Fees to close and refund a reserve. * Fees to close and refund a reserve.
*/ */

View File

@ -25,6 +25,7 @@ import * as nacl from "./nacl-fast.js";
import { kdf, kdfKw } from "./kdf.js"; import { kdf, kdfKw } from "./kdf.js";
import bigint from "big-integer"; import bigint from "big-integer";
import { import {
Base32String,
CoinEnvelope, CoinEnvelope,
DenominationPubKey, DenominationPubKey,
DenomKeyType, DenomKeyType,
@ -598,6 +599,15 @@ export function hash(d: Uint8Array): Uint8Array {
return nacl.hash(d); return nacl.hash(d);
} }
/**
* Hash the input with SHA-512 and truncate the result
* to 32 bytes.
*/
export function hashTruncate32(d: Uint8Array): Uint8Array {
const sha512HashCode = nacl.hash(d);
return sha512HashCode.subarray(0, 32);
}
export function hashCoinEv( export function hashCoinEv(
coinEv: CoinEnvelope, coinEv: CoinEnvelope,
denomPubHash: HashCodeString, denomPubHash: HashCodeString,
@ -608,7 +618,6 @@ export function hashCoinEv(
return hashContext.finish(); return hashContext.finish();
} }
const logger = new Logger("talerCrypto.ts"); const logger = new Logger("talerCrypto.ts");
export function hashCoinEvInner( export function hashCoinEvInner(
@ -683,7 +692,6 @@ export interface FreshCoin {
bks: Uint8Array; bks: Uint8Array;
} }
function bufferForUint32(n: number): Uint8Array { function bufferForUint32(n: number): Uint8Array {
const arrBuf = new ArrayBuffer(4); const arrBuf = new ArrayBuffer(4);
const buf = new Uint8Array(arrBuf); const buf = new Uint8Array(arrBuf);

View File

@ -738,6 +738,8 @@ export class WireFeesJson {
*/ */
wire_fee: string; wire_fee: string;
wad_fee: string;
/** /**
* Cost of clising a reserve. * Cost of clising a reserve.
*/ */
@ -1356,6 +1358,7 @@ export const codecForWireFeesJson = (): Codec<WireFeesJson> =>
buildCodecForObject<WireFeesJson>() buildCodecForObject<WireFeesJson>()
.property("wire_fee", codecForString()) .property("wire_fee", codecForString())
.property("closing_fee", codecForString()) .property("closing_fee", codecForString())
.property("wad_fee", codecForString())
.property("sig", codecForString()) .property("sig", codecForString())
.property("start_date", codecForTimestamp) .property("start_date", codecForTimestamp)
.property("end_date", codecForTimestamp) .property("end_date", codecForTimestamp)

View File

@ -1443,6 +1443,7 @@ export class ExchangeService implements ExchangeServiceInterface {
accTargetType, accTargetType,
`${this.exchangeConfig.currency}:0.01`, `${this.exchangeConfig.currency}:0.01`,
`${this.exchangeConfig.currency}:0.01`, `${this.exchangeConfig.currency}:0.01`,
`${this.exchangeConfig.currency}:0.01`,
"upload", "upload",
], ],
); );

View File

@ -48,6 +48,7 @@ import {
hashCoinEv, hashCoinEv,
hashCoinEvInner, hashCoinEvInner,
hashDenomPub, hashDenomPub,
hashTruncate32,
keyExchangeEcdheEddsa, keyExchangeEcdheEddsa,
Logger, Logger,
MakeSyncSignatureRequest, MakeSyncSignatureRequest,
@ -329,6 +330,7 @@ export class CryptoImplementation {
.put(timestampRoundedToBuffer(wf.endStamp)) .put(timestampRoundedToBuffer(wf.endStamp))
.put(amountToBuffer(wf.wireFee)) .put(amountToBuffer(wf.wireFee))
.put(amountToBuffer(wf.closingFee)) .put(amountToBuffer(wf.closingFee))
.put(amountToBuffer(wf.wadFee))
.build(); .build();
const sig = decodeCrock(wf.sig); const sig = decodeCrock(wf.sig);
const pub = decodeCrock(masterPub); const pub = decodeCrock(masterPub);
@ -376,7 +378,7 @@ export class CryptoImplementation {
sig: string, sig: string,
masterPub: string, masterPub: string,
): boolean { ): boolean {
const paytoHash = hash(stringToBytes(paytoUri + "\0")); const paytoHash = hashTruncate32(stringToBytes(paytoUri + "\0"));
const p = buildSigPS(TalerSignaturePurpose.MASTER_WIRE_DETAILS) const p = buildSigPS(TalerSignaturePurpose.MASTER_WIRE_DETAILS)
.put(paytoHash) .put(paytoHash)
.build(); .build();

View File

@ -1026,6 +1026,11 @@ export interface WireFee {
*/ */
closingFee: AmountJson; closingFee: AmountJson;
/**
* Fees for inter-exchange transfers from P2P payments.
*/
wadFee: AmountJson;
/** /**
* Start date of the fee. * Start date of the fee.
*/ */

View File

@ -113,9 +113,8 @@ export async function exportBackup(
} = {}; } = {};
await tx.withdrawalGroups.iter().forEachAsync(async (wg) => { await tx.withdrawalGroups.iter().forEachAsync(async (wg) => {
const withdrawalGroups = (withdrawalGroupsByReserve[ const withdrawalGroups = (withdrawalGroupsByReserve[wg.reservePub] ??=
wg.reservePub []);
] ??= []);
withdrawalGroups.push({ withdrawalGroups.push({
raw_withdrawal_amount: Amounts.stringify(wg.rawWithdrawalAmount), raw_withdrawal_amount: Amounts.stringify(wg.rawWithdrawalAmount),
selected_denoms: wg.denomsSel.selectedDenoms.map((x) => ({ selected_denoms: wg.denomsSel.selectedDenoms.map((x) => ({
@ -288,6 +287,7 @@ export async function exportBackup(
wireFees.push({ wireFees.push({
wire_type: x, wire_type: x,
closing_fee: Amounts.stringify(f.closingFee), closing_fee: Amounts.stringify(f.closingFee),
wad_fee: Amounts.stringify(f.wadFee),
end_stamp: f.endStamp, end_stamp: f.endStamp,
sig: f.sig, sig: f.sig,
start_stamp: f.startStamp, start_stamp: f.startStamp,

View File

@ -305,6 +305,7 @@ export async function importBackup(
sig: fee.sig, sig: fee.sig,
startStamp: fee.start_stamp, startStamp: fee.start_stamp,
wireFee: Amounts.parseOrThrow(fee.wire_fee), wireFee: Amounts.parseOrThrow(fee.wire_fee),
wadFee: Amounts.parseOrThrow(fee.wad_fee),
}); });
} }
await tx.exchangeDetails.put({ await tx.exchangeDetails.put({

View File

@ -266,6 +266,7 @@ async function validateWireInfo(
sig: x.sig, sig: x.sig,
startStamp, startStamp,
wireFee: Amounts.parseOrThrow(x.wire_fee), wireFee: Amounts.parseOrThrow(x.wire_fee),
wadFee: Amounts.parseOrThrow(x.wad_fee),
}; };
let isValid = false; let isValid = false;
if (ws.insecureTrustExchange) { if (ws.insecureTrustExchange) {
@ -451,7 +452,8 @@ export async function downloadTosFromAcceptedFormat(
ws: InternalWalletState, ws: InternalWalletState,
baseUrl: string, baseUrl: string,
timeout: Duration, timeout: Duration,
acceptedFormat?: string[]): Promise<ExchangeTosDownloadResult> { acceptedFormat?: string[],
): Promise<ExchangeTosDownloadResult> {
let tosFound: ExchangeTosDownloadResult | undefined; let tosFound: ExchangeTosDownloadResult | undefined;
//Remove this when exchange supports multiple content-type in accept header //Remove this when exchange supports multiple content-type in accept header
if (acceptedFormat) if (acceptedFormat)
@ -467,7 +469,7 @@ export async function downloadTosFromAcceptedFormat(
break; break;
} }
} }
if (tosFound !== undefined) return tosFound if (tosFound !== undefined) return tosFound;
// If none of the specified format was found try text/plain // If none of the specified format was found try text/plain
return await downloadExchangeWithTermsOfService( return await downloadExchangeWithTermsOfService(
baseUrl, baseUrl,
@ -550,8 +552,12 @@ async function updateExchangeFromUrlImpl(
logger.info("finished validating exchange /wire info"); logger.info("finished validating exchange /wire info");
const tosDownload = await downloadTosFromAcceptedFormat(
const tosDownload = await downloadTosFromAcceptedFormat(ws, baseUrl, timeout, acceptedFormat) ws,
baseUrl,
timeout,
acceptedFormat,
);
let recoupGroupId: string | undefined; let recoupGroupId: string | undefined;