fix and test case for "insecure" taler://refund URIs

This commit is contained in:
Florian Dold 2020-01-18 23:32:03 +01:00
parent fcb0565323
commit af57a404d0
No known key found for this signature in database
GPG Key ID: D2E4F00F29D02A4B
6 changed files with 53 additions and 11 deletions

View File

@ -171,6 +171,8 @@ export async function runIntegrationTest(args: IntegrationTestArgs) {
Amounts.toString(refundAmount), Amounts.toString(refundAmount),
); );
console.log("refund URI", refundUri);
await myWallet.applyRefund(refundUri); await myWallet.applyRefund(refundUri);
// Wait until the refund is done // Wait until the refund is done

View File

@ -1093,6 +1093,7 @@ export async function confirmPay(
); );
logger.trace("confirmPay: submitting payment after creating purchase record"); logger.trace("confirmPay: submitting payment after creating purchase record");
logger.trace("purchaseRecord:", purchase);
return submitPay(ws, proposalId); return submitPay(ws, proposalId);
} }

View File

@ -271,7 +271,7 @@ export async function applyRefund(
): Promise<string> { ): Promise<string> {
const parseResult = parseRefundUri(talerRefundUri); const parseResult = parseRefundUri(talerRefundUri);
console.log("applying refund"); console.log("applying refund", parseResult);
if (!parseResult) { if (!parseResult) {
throw Error("invalid refund URI"); throw Error("invalid refund URI");
@ -283,7 +283,7 @@ export async function applyRefund(
]); ]);
if (!purchase) { if (!purchase) {
throw Error("no purchase for the taler://refund/ URI was found"); throw Error(`no purchase for the taler://refund/ URI (${talerRefundUri}) was found`);
} }
console.log("processing purchase for refund"); console.log("processing purchase for refund");

View File

@ -96,7 +96,7 @@ test("taler pay url parsing: complex path prefix", t => {
t.is(r1.sessionId, undefined); t.is(r1.sessionId, undefined);
}); });
test("taler pay url parsing: complex path prefix and instance", t => { test("taler pay uri parsing: complex path prefix and instance", t => {
const url1 = "taler://pay/example.com/mypfx%2Fpublic/foo/myorder"; const url1 = "taler://pay/example.com/mypfx%2Fpublic/foo/myorder";
const r1 = parsePayUri(url1); const r1 = parsePayUri(url1);
if (!r1) { if (!r1) {
@ -107,7 +107,18 @@ test("taler pay url parsing: complex path prefix and instance", t => {
t.is(r1.orderId, "myorder"); t.is(r1.orderId, "myorder");
}); });
test("taler pay url parsing: non-https #1", t => { test("taler refund uri parsing: non-https #1", t => {
const url1 = "taler://refund/example.com/-/-/myorder?insecure=1";
const r1 = parseRefundUri(url1);
if (!r1) {
t.fail();
return;
}
t.is(r1.merchantBaseUrl, "http://example.com/public/");
t.is(r1.orderId, "myorder")
});
test("taler pay uri parsing: non-https #1", t => {
const url1 = "taler://pay/example.com/-/-/myorder?insecure=1"; const url1 = "taler://pay/example.com/-/-/myorder?insecure=1";
const r1 = parsePayUri(url1); const r1 = parsePayUri(url1);
if (!r1) { if (!r1) {

View File

@ -95,13 +95,12 @@ export function classifyTalerUri(s: string): TalerUriType {
return TalerUriType.TalerNotifyReserve; return TalerUriType.TalerNotifyReserve;
} }
return TalerUriType.Unknown; return TalerUriType.Unknown;
} }
export function getOrderDownloadUrl(merchantBaseUrl: string, orderId: string) { export function getOrderDownloadUrl(merchantBaseUrl: string, orderId: string) {
const u = new URL("proposal", merchantBaseUrl); const u = new URL("proposal", merchantBaseUrl);
u.searchParams.set("order_id", orderId); u.searchParams.set("order_id", orderId);
return u.href return u.href;
} }
export function parsePayUri(s: string): PayUriResult | undefined { export function parsePayUri(s: string): PayUriResult | undefined {
@ -208,7 +207,7 @@ export function parseRefundUri(s: string): RefundUriResult | undefined {
return undefined; return undefined;
} }
const path = s.slice(pfx.length); const [path, search] = s.slice(pfx.length).split("?");
let [host, maybePath, maybeInstance, orderId] = path.split("/"); let [host, maybePath, maybeInstance, orderId] = path.split("/");
@ -236,10 +235,14 @@ export function parseRefundUri(s: string): RefundUriResult | undefined {
maybeInstancePath = `instances/${maybeInstance}/`; maybeInstancePath = `instances/${maybeInstance}/`;
} }
const merchantBaseUrl = "https://" + host + let protocol = "https";
"/" + const searchParams = new URLSearchParams(search);
maybePath + if (searchParams.get("insecure") === "1") {
maybeInstancePath protocol = "http";
}
const merchantBaseUrl =
`${protocol}://${host}/` + maybePath + maybeInstancePath;
return { return {
merchantBaseUrl, merchantBaseUrl,

View File

@ -241,6 +241,31 @@ export class Wallet {
* returns without resolving to an exception. * returns without resolving to an exception.
*/ */
public async runUntilDone(): Promise<void> { public async runUntilDone(): Promise<void> {
const p = new Promise((resolve, reject) => {
// Run this asynchronously
this.addNotificationListener(n => {
if (
n.type === NotificationType.WaitingForRetry &&
n.numGivingLiveness == 0
) {
logger.trace("no liveness-giving operations left, returning");
resolve();
}
});
this.runRetryLoop().catch(e => {
console.log("exception in wallet retry loop");
reject(e);
});
});
await p;
}
/**
* Run the wallet until there are no more pending operations that give
* liveness left. The wallet will be in a stopped state when this function
* returns without resolving to an exception.
*/
public async runUntilDoneAndStop(): Promise<void> {
const p = new Promise((resolve, reject) => { const p = new Promise((resolve, reject) => {
// Run this asynchronously // Run this asynchronously
this.addNotificationListener(n => { this.addNotificationListener(n => {