support for talerpay URLs with session ID

This commit is contained in:
Florian Dold 2019-08-24 18:42:00 +02:00
parent 87fdafb1a5
commit d454f7547d
No known key found for this signature in database
GPG Key ID: D2E4F00F29D02A4B
3 changed files with 42 additions and 21 deletions

View File

@ -156,7 +156,7 @@ export function installAndroidWalletListener() {
} }
case "confirmPay": { case "confirmPay": {
const wallet = await wp.promise; const wallet = await wp.promise;
result = await wallet.confirmPay(msg.args.proposalId, undefined); result = await wallet.confirmPay(msg.args.proposalId, msg.args.sessionId);
break; break;
} }
case "startTunnel": { case "startTunnel": {

View File

@ -545,6 +545,12 @@ export class ProposalDownloadRecord {
@Checkable.String() @Checkable.String()
noncePriv: string; noncePriv: string;
/**
* Session ID we got when downloading the contract.
*/
@Checkable.Optional(Checkable.String())
downloadSessionId?: string;
/** /**
* Verify that a value matches the schema of this class and convert it into a * Verify that a value matches the schema of this class and convert it into a
* member. * member.

View File

@ -381,8 +381,7 @@ export class Wallet {
} }
private async fillDefaults() { private async fillDefaults() {
const onTrue = (r: QueryRoot) => { const onTrue = (r: QueryRoot) => {};
};
const onFalse = (r: QueryRoot) => { const onFalse = (r: QueryRoot) => {
Wallet.enableTracing && console.log("applying defaults"); Wallet.enableTracing && console.log("applying defaults");
r.put(Stores.config, { key: "currencyDefaultsApplied", value: true }) r.put(Stores.config, { key: "currencyDefaultsApplied", value: true })
@ -428,19 +427,19 @@ export class Wallet {
* by looking at the database. * by looking at the database.
*/ */
private resumePendingFromDb(): void { private resumePendingFromDb(): void {
console.log("resuming pending operations from db"); Wallet.enableTracing && console.log("resuming pending operations from db");
this.q() this.q()
.iter(Stores.reserves) .iter(Stores.reserves)
.forEach(reserve => { .forEach(reserve => {
console.log("resuming reserve", reserve.reserve_pub); Wallet.enableTracing && console.log("resuming reserve", reserve.reserve_pub);
this.processReserve(reserve.reserve_pub); this.processReserve(reserve.reserve_pub);
}); });
this.q() this.q()
.iter(Stores.precoins) .iter(Stores.precoins)
.forEach(preCoin => { .forEach(preCoin => {
console.log("resuming precoin"); Wallet.enableTracing && console.log("resuming precoin");
this.processPreCoin(preCoin.coinPub); this.processPreCoin(preCoin.coinPub);
}); });
@ -461,7 +460,7 @@ export class Wallet {
.iter(Stores.coins) .iter(Stores.coins)
.forEach((c: CoinRecord) => { .forEach((c: CoinRecord) => {
if (c.status === CoinStatus.Dirty) { if (c.status === CoinStatus.Dirty) {
console.log("resuming pending refresh for coin", c); Wallet.enableTracing && console.log("resuming pending refresh for coin", c);
this.refresh(c.coinPub); this.refresh(c.coinPub);
} }
}); });
@ -592,8 +591,6 @@ export class Wallet {
.iterIndex(Stores.coins.exchangeBaseUrlIndex, exchange.baseUrl) .iterIndex(Stores.coins.exchangeBaseUrlIndex, exchange.baseUrl)
.toArray(); .toArray();
console.log("considering coins", coins);
const denoms = await this.q() const denoms = await this.q()
.iterIndex(Stores.denominations.exchangeBaseUrlIndex, exchange.baseUrl) .iterIndex(Stores.denominations.exchangeBaseUrlIndex, exchange.baseUrl)
.toArray(); .toArray();
@ -720,15 +717,18 @@ export class Wallet {
} }
async preparePay(url: string): Promise<PreparePayResult> { async preparePay(url: string): Promise<PreparePayResult> {
const talerpayPrefix = "talerpay:" const talerpayPrefix = "talerpay:";
let downloadSessionId: string | undefined;
if (url.startsWith(talerpayPrefix)) { if (url.startsWith(talerpayPrefix)) {
url = decodeURIComponent(url.substring(talerpayPrefix.length)); let [p1, p2] = url.substring(talerpayPrefix.length).split(";");
url = decodeURIComponent(p1);
downloadSessionId = p2;
} }
let proposalId: number; let proposalId: number;
let checkResult: CheckPayResult; let checkResult: CheckPayResult;
try { try {
console.log("downloading proposal"); console.log("downloading proposal");
proposalId = await this.downloadProposal(url); proposalId = await this.downloadProposal(url, downloadSessionId);
console.log("calling checkPay"); console.log("calling checkPay");
checkResult = await this.checkPay(proposalId); checkResult = await this.checkPay(proposalId);
console.log("checkPay result", checkResult); console.log("checkPay result", checkResult);
@ -736,7 +736,7 @@ export class Wallet {
return { return {
status: "error", status: "error",
error: e.toString(), error: e.toString(),
} };
} }
const proposal = await this.getProposal(proposalId); const proposal = await this.getProposal(proposalId);
if (!proposal) { if (!proposal) {
@ -770,13 +770,19 @@ export class Wallet {
/** /**
* Download a proposal and store it in the database. * Download a proposal and store it in the database.
* Returns an id for it to retrieve it later. * Returns an id for it to retrieve it later.
*
* @param sessionId Current session ID, if the proposal is being
* downloaded in the context of a session ID.
*/ */
async downloadProposal(url: string): Promise<number> { async downloadProposal(url: string, sessionId?: string): Promise<number> {
console.log("downloading proposal from", url);
console.log("context session id is", sessionId);
const oldProposal = await this.q().getIndexed( const oldProposal = await this.q().getIndexed(
Stores.proposals.urlIndex, Stores.proposals.urlIndex,
url, url,
); );
if (oldProposal) { if (oldProposal) {
console.log("old proposal exists:", oldProposal);
return oldProposal.id!; return oldProposal.id!;
} }
@ -803,6 +809,7 @@ export class Wallet {
noncePriv: priv, noncePriv: priv,
timestamp: new Date().getTime(), timestamp: new Date().getTime(),
url, url,
downloadSessionId: sessionId,
}; };
const id = await this.q().putWithResult(Stores.proposals, proposalRecord); const id = await this.q().putWithResult(Stores.proposals, proposalRecord);
@ -852,7 +859,7 @@ export class Wallet {
const payReq = { ...purchase.payReq, session_id: sessionId }; const payReq = { ...purchase.payReq, session_id: sessionId };
try { try {
resp = await this.http.postJson(purchase.contractTerms.pay_url, payReq) resp = await this.http.postJson(purchase.contractTerms.pay_url, payReq);
} catch (e) { } catch (e) {
// Gives the user the option to retry / abort and refresh // Gives the user the option to retry / abort and refresh
console.log("payment failed", e); console.log("payment failed", e);
@ -913,10 +920,10 @@ export class Wallet {
*/ */
async confirmPay( async confirmPay(
proposalId: number, proposalId: number,
sessionId: string | undefined, sessionIdOverride: string | undefined,
): Promise<ConfirmPayResult> { ): Promise<ConfirmPayResult> {
console.log( console.log(
`executing confirmPay with proposalId ${proposalId} and sessionId ${sessionId}`, `executing confirmPay with proposalId ${proposalId} and sessionIdOverride ${sessionIdOverride}`,
); );
const proposal: ProposalDownloadRecord | undefined = await this.q().get( const proposal: ProposalDownloadRecord | undefined = await this.q().get(
Stores.proposals, Stores.proposals,
@ -927,6 +934,8 @@ export class Wallet {
throw Error(`proposal with id ${proposalId} not found`); throw Error(`proposal with id ${proposalId} not found`);
} }
const sessionId = sessionIdOverride || proposal.downloadSessionId;
let purchase = await this.q().get( let purchase = await this.q().get(
Stores.purchases, Stores.purchases,
proposal.contractTermsHash, proposal.contractTermsHash,
@ -1028,6 +1037,9 @@ export class Wallet {
* look faster to the user. * look faster to the user.
*/ */
async checkPay(proposalId: number): Promise<CheckPayResult> { async checkPay(proposalId: number): Promise<CheckPayResult> {
console.log("doing checkPay for proposalId", proposalId)
const proposal = await this.q().get(Stores.proposals, proposalId); const proposal = await this.q().get(Stores.proposals, proposalId);
if (!proposal) { if (!proposal) {
@ -1040,12 +1052,16 @@ export class Wallet {
proposal.contractTermsHash, proposal.contractTermsHash,
); );
if (purchase) { if (purchase) {
console.log("got purchase", purchase)
return { status: "paid" }; return { status: "paid" };
} }
const paymentAmount = Amounts.parseOrThrow(proposal.contractTerms.amount); const paymentAmount = Amounts.parseOrThrow(proposal.contractTerms.amount);
Wallet.enableTracing && console.log(`checking if payment of ${JSON.stringify(paymentAmount)} is possible`); Wallet.enableTracing &&
console.log(
`checking if payment of ${JSON.stringify(paymentAmount)} is possible`,
);
let wireFeeLimit; let wireFeeLimit;
if (proposal.contractTerms.max_wire_fee) { if (proposal.contractTerms.max_wire_fee) {
@ -2317,7 +2333,7 @@ export class Wallet {
.iter(Stores.refresh) .iter(Stores.refresh)
.toArray(); .toArray();
for (const session of oldRefreshSessions) { for (const session of oldRefreshSessions) {
console.log("got old session for", oldCoinPub, session); Wallet.enableTracing && console.log("got old refresh session for", oldCoinPub, session);
this.continueRefreshSession(session); this.continueRefreshSession(session);
} }
const coin = await this.q().get(Stores.coins, oldCoinPub); const coin = await this.q().get(Stores.coins, oldCoinPub);
@ -2537,7 +2553,7 @@ export class Wallet {
// We uniquely identify history rows via their timestamp. // We uniquely identify history rows via their timestamp.
// This works as timestamps are guaranteed to be monotonically // This works as timestamps are guaranteed to be monotonically
// increasing even // increasing even
const proposals = await this.q() const proposals = await this.q()
.iter<ProposalDownloadRecord>(Stores.proposals) .iter<ProposalDownloadRecord>(Stores.proposals)
@ -3418,7 +3434,6 @@ export class Wallet {
*/ */
async collectGarbage() { async collectGarbage() {
// FIXME(#5845) // FIXME(#5845)
// We currently do not garbage-collect the wallet database. This might change // We currently do not garbage-collect the wallet database. This might change
// after the feature has been properly re-designed, and we have come up with a // after the feature has been properly re-designed, and we have come up with a
// strategy to test it. // strategy to test it.