new fulfillment protocol
This commit is contained in:
parent
b150470eb6
commit
42a0076f59
@ -17,19 +17,22 @@
|
||||
// query the availability of Taler.
|
||||
/// <reference path="../lib/decl/chrome/chrome.d.ts" />
|
||||
"use strict";
|
||||
console.log("Taler injected");
|
||||
function subst(url, H_contract) {
|
||||
// Make sure we don't pollute the namespace too much.
|
||||
var TalerNotify;
|
||||
(function (TalerNotify) {
|
||||
console.log("Taler injected");
|
||||
function subst(url, H_contract) {
|
||||
url = url.replace("${H_contract}", H_contract);
|
||||
url = url.replace("${$}", "$");
|
||||
return url;
|
||||
}
|
||||
document.addEventListener("taler-probe", function (e) {
|
||||
}
|
||||
var $ = function (x) { return document.getElementById(x); };
|
||||
document.addEventListener("taler-probe", function (e) {
|
||||
var evt = new Event("taler-wallet-present");
|
||||
document.dispatchEvent(evt);
|
||||
console.log("handshake done");
|
||||
});
|
||||
document.addEventListener("taler-create-reserve", function (e) {
|
||||
var $ = function (x) { return document.getElementById(x); };
|
||||
});
|
||||
document.addEventListener("taler-create-reserve", function (e) {
|
||||
console.log("taler-create-reserve with " + JSON.stringify(e.detail));
|
||||
var form_uri = $(e.detail.form_id).action;
|
||||
// TODO: validate event fields
|
||||
@ -46,19 +49,18 @@ document.addEventListener("taler-create-reserve", function (e) {
|
||||
};
|
||||
var uri = URI(chrome.extension.getURL("pages/confirm-create-reserve.html"));
|
||||
document.location.href = uri.query(params).href();
|
||||
});
|
||||
document.addEventListener("taler-contract", function (e) {
|
||||
});
|
||||
document.addEventListener("taler-contract", function (e) {
|
||||
// XXX: the merchant should just give us the parsed data ...
|
||||
var offer = JSON.parse(e.detail);
|
||||
var uri = URI(chrome.extension.getURL("pages/confirm-contract.html"));
|
||||
var params = {
|
||||
offer: JSON.stringify(offer),
|
||||
merchantPageUrl: document.location.href,
|
||||
cookie: document.cookie,
|
||||
};
|
||||
document.location.href = uri.query(params).href();
|
||||
});
|
||||
document.addEventListener('taler-execute-payment', function (e) {
|
||||
});
|
||||
document.addEventListener('taler-execute-payment', function (e) {
|
||||
console.log("got taler-execute-payment in content page");
|
||||
if (!e.detail.pay_url) {
|
||||
console.log("field 'pay_url' missing in taler-execute-payment event");
|
||||
@ -72,26 +74,34 @@ document.addEventListener('taler-execute-payment', function (e) {
|
||||
},
|
||||
};
|
||||
chrome.runtime.sendMessage(msg, function (resp) {
|
||||
console.log("got resp");
|
||||
console.dir(resp);
|
||||
if (!resp.success) {
|
||||
console.log("failure!");
|
||||
console.log("got event detial:");
|
||||
console.dir(e.detail);
|
||||
if (e.detail.offering_url) {
|
||||
console.log("offering url", e.detail.offering_url);
|
||||
window.location.href = e.detail.offering_url;
|
||||
}
|
||||
else {
|
||||
console.error("execute-payment failed");
|
||||
}
|
||||
return;
|
||||
}
|
||||
var contract = resp.contract;
|
||||
if (!contract) {
|
||||
throw Error("contract missing");
|
||||
}
|
||||
var payReq = Object.assign({}, resp.payReq);
|
||||
if (e.detail.require_contract) {
|
||||
payReq.contract = contract;
|
||||
}
|
||||
console.log("Making request to ", payUrl);
|
||||
var r = new XMLHttpRequest();
|
||||
r.open('post', payUrl);
|
||||
r.send(JSON.stringify(payReq));
|
||||
r.send(JSON.stringify(resp.payReq));
|
||||
r.onload = function () {
|
||||
switch (r.status) {
|
||||
case 200:
|
||||
console.log("going to", contract.fulfillment_url);
|
||||
// TODO: Is this the right thing? Does the reload
|
||||
// TODO: override setting location.href?
|
||||
window.location.href = subst(contract.fulfillment_url, e.detail.H_contract);
|
||||
window.location.reload(true);
|
||||
break;
|
||||
@ -101,5 +111,6 @@ document.addEventListener('taler-execute-payment', function (e) {
|
||||
}
|
||||
};
|
||||
});
|
||||
});
|
||||
});
|
||||
})(TalerNotify || (TalerNotify = {}));
|
||||
//# sourceMappingURL=notify.js.map
|
@ -21,23 +21,26 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
console.log("Taler injected");
|
||||
|
||||
function subst(url: string, H_contract) {
|
||||
// Make sure we don't pollute the namespace too much.
|
||||
namespace TalerNotify {
|
||||
console.log("Taler injected");
|
||||
|
||||
function subst(url: string, H_contract) {
|
||||
url = url.replace("${H_contract}", H_contract);
|
||||
url = url.replace("${$}", "$");
|
||||
return url;
|
||||
}
|
||||
}
|
||||
|
||||
let $ = (x) => document.getElementById(x);
|
||||
|
||||
document.addEventListener("taler-probe", function(e) {
|
||||
document.addEventListener("taler-probe", function(e) {
|
||||
let evt = new Event("taler-wallet-present");
|
||||
document.dispatchEvent(evt);
|
||||
console.log("handshake done");
|
||||
});
|
||||
});
|
||||
|
||||
document.addEventListener("taler-create-reserve", function(e: CustomEvent) {
|
||||
let $ = (x) => document.getElementById(x);
|
||||
document.addEventListener("taler-create-reserve", function(e: CustomEvent) {
|
||||
console.log("taler-create-reserve with " + JSON.stringify(e.detail));
|
||||
let form_uri = (<HTMLFormElement>$(e.detail.form_id)).action;
|
||||
// TODO: validate event fields
|
||||
@ -54,23 +57,22 @@ document.addEventListener("taler-create-reserve", function(e: CustomEvent) {
|
||||
};
|
||||
let uri = URI(chrome.extension.getURL("pages/confirm-create-reserve.html"));
|
||||
document.location.href = uri.query(params).href();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
document.addEventListener("taler-contract", function(e: CustomEvent) {
|
||||
document.addEventListener("taler-contract", function(e: CustomEvent) {
|
||||
// XXX: the merchant should just give us the parsed data ...
|
||||
let offer = JSON.parse(e.detail);
|
||||
let uri = URI(chrome.extension.getURL("pages/confirm-contract.html"));
|
||||
let params = {
|
||||
offer: JSON.stringify(offer),
|
||||
merchantPageUrl: document.location.href,
|
||||
cookie: document.cookie,
|
||||
};
|
||||
document.location.href = uri.query(params).href();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
document.addEventListener('taler-execute-payment', function(e: CustomEvent) {
|
||||
document.addEventListener('taler-execute-payment', function(e: CustomEvent) {
|
||||
console.log("got taler-execute-payment in content page");
|
||||
if (!e.detail.pay_url) {
|
||||
console.log("field 'pay_url' missing in taler-execute-payment event");
|
||||
@ -84,8 +86,17 @@ document.addEventListener('taler-execute-payment', function(e: CustomEvent) {
|
||||
},
|
||||
};
|
||||
chrome.runtime.sendMessage(msg, (resp) => {
|
||||
console.log("got resp");
|
||||
console.dir(resp);
|
||||
if (!resp.success) {
|
||||
console.log("failure!");
|
||||
console.log("got event detial:");
|
||||
console.dir(e.detail);
|
||||
if (e.detail.offering_url) {
|
||||
console.log("offering url", e.detail.offering_url);
|
||||
window.location.href = e.detail.offering_url;
|
||||
} else {
|
||||
console.error("execute-payment failed");
|
||||
}
|
||||
return;
|
||||
}
|
||||
let contract = resp.contract;
|
||||
@ -93,19 +104,16 @@ document.addEventListener('taler-execute-payment', function(e: CustomEvent) {
|
||||
throw Error("contract missing");
|
||||
}
|
||||
|
||||
let payReq = Object.assign({}, resp.payReq);
|
||||
if (e.detail.require_contract) {
|
||||
payReq.contract = contract;
|
||||
}
|
||||
|
||||
console.log("Making request to ", payUrl);
|
||||
let r = new XMLHttpRequest();
|
||||
r.open('post', payUrl);
|
||||
r.send(JSON.stringify(payReq));
|
||||
r.send(JSON.stringify(resp.payReq));
|
||||
r.onload = () => {
|
||||
switch (r.status) {
|
||||
case 200:
|
||||
console.log("going to", contract.fulfillment_url);
|
||||
// TODO: Is this the right thing? Does the reload
|
||||
// TODO: override setting location.href?
|
||||
window.location.href = subst(contract.fulfillment_url,
|
||||
e.detail.H_contract);
|
||||
window.location.reload(true);
|
||||
@ -116,4 +124,5 @@ document.addEventListener('taler-execute-payment', function(e: CustomEvent) {
|
||||
}
|
||||
};
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
2178
extension/lib/decl/node.d.ts
vendored
Normal file
2178
extension/lib/decl/node.d.ts
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,136 +0,0 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
(C) 2016 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 3, or (at your option) any later version.
|
||||
|
||||
TALER is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Decorators for type-checking JSON into
|
||||
* an object.
|
||||
* @module Checkable
|
||||
* @author Florian Dold
|
||||
*/
|
||||
|
||||
export namespace Checkable {
|
||||
let chkSym = Symbol("checkable");
|
||||
|
||||
function checkNumber(target, prop): any {
|
||||
if ((typeof target) !== "number") {
|
||||
throw Error("number expected for " + prop.propertyKey);
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
function checkString(target, prop): any {
|
||||
if (typeof target !== "string") {
|
||||
throw Error("string expected for " + prop.propertyKey);
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
function checkAnyObject(target, prop): any {
|
||||
if (typeof target !== "object") {
|
||||
throw Error("object expected for " + prop.propertyKey);
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
function checkValue(target, prop): any {
|
||||
let type = prop.type;
|
||||
if (!type) {
|
||||
throw Error("assertion failed");
|
||||
}
|
||||
let v = target;
|
||||
if (!v || typeof v !== "object") {
|
||||
throw Error("expected object for " + prop.propertyKey);
|
||||
}
|
||||
let props = type.prototype[chkSym].props;
|
||||
let remainingPropNames = new Set(Object.getOwnPropertyNames(v));
|
||||
let obj = new type();
|
||||
for (let prop of props) {
|
||||
if (!remainingPropNames.has(prop.propertyKey)) {
|
||||
throw Error("Property missing: " + prop.propertyKey);
|
||||
}
|
||||
if (!remainingPropNames.delete(prop.propertyKey)) {
|
||||
throw Error("assertion failed");
|
||||
}
|
||||
let propVal = v[prop.propertyKey];
|
||||
obj[prop.propertyKey] = prop.checker(propVal, prop);
|
||||
}
|
||||
|
||||
if (remainingPropNames.size != 0) {
|
||||
throw Error("superfluous properties " + JSON.stringify(Array.from(
|
||||
remainingPropNames.values())));
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
export function Class(target) {
|
||||
target.checked = (v) => {
|
||||
return checkValue(v, {
|
||||
propertyKey: "(root)",
|
||||
type: target,
|
||||
checker: checkValue
|
||||
});
|
||||
};
|
||||
return target;
|
||||
}
|
||||
|
||||
export function Value(type) {
|
||||
function deco(target: Object, propertyKey: string | symbol): void {
|
||||
let chk = mkChk(target);
|
||||
chk.props.push({
|
||||
propertyKey: propertyKey,
|
||||
checker: checkValue,
|
||||
type: type
|
||||
});
|
||||
}
|
||||
|
||||
return deco;
|
||||
}
|
||||
|
||||
export function List(type) {
|
||||
function deco(target: Object, propertyKey: string | symbol): void {
|
||||
throw Error("not implemented");
|
||||
}
|
||||
|
||||
return deco;
|
||||
}
|
||||
|
||||
export function Number(target: Object, propertyKey: string | symbol): void {
|
||||
let chk = mkChk(target);
|
||||
chk.props.push({propertyKey: propertyKey, checker: checkNumber});
|
||||
}
|
||||
|
||||
export function AnyObject(target: Object, propertyKey: string | symbol): void {
|
||||
let chk = mkChk(target);
|
||||
chk.props.push({propertyKey: propertyKey, checker: checkAnyObject});
|
||||
}
|
||||
|
||||
export function String(target: Object, propertyKey: string | symbol): void {
|
||||
let chk = mkChk(target);
|
||||
chk.props.push({propertyKey: propertyKey, checker: checkString});
|
||||
}
|
||||
|
||||
function mkChk(target) {
|
||||
let chk = target[chkSym];
|
||||
if (!chk) {
|
||||
chk = {props: []};
|
||||
target[chkSym] = chk;
|
||||
}
|
||||
return chk;
|
||||
}
|
||||
}
|
@ -14,7 +14,7 @@
|
||||
TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
import {AmountJson_interface} from "./types";
|
||||
import {AmountJson} from "./types";
|
||||
import * as EmscWrapper from "../emscripten/emsc";
|
||||
|
||||
/**
|
||||
@ -288,7 +288,7 @@ arenaStack.push(new SyncArena());
|
||||
|
||||
|
||||
export class Amount extends ArenaObject {
|
||||
constructor(args?: AmountJson_interface, arena?: Arena) {
|
||||
constructor(args?: AmountJson, arena?: Arena) {
|
||||
super(arena);
|
||||
if (args) {
|
||||
this.nativePtr = emscAlloc.get_amount(args.value,
|
||||
|
@ -14,8 +14,6 @@
|
||||
TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/// <reference path="../decl/urijs/URIjs.d.ts" />
|
||||
|
||||
|
||||
/**
|
||||
* Database query abstractions.
|
||||
|
@ -33,10 +33,10 @@ export interface Keys {
|
||||
}
|
||||
|
||||
export interface Denomination {
|
||||
value: AmountJson_interface;
|
||||
value: AmountJson;
|
||||
denom_pub: string;
|
||||
fee_withdraw: AmountJson_interface;
|
||||
fee_deposit: AmountJson_interface;
|
||||
fee_withdraw: AmountJson;
|
||||
fee_deposit: AmountJson;
|
||||
}
|
||||
|
||||
export interface PreCoin {
|
||||
@ -48,7 +48,7 @@ export interface PreCoin {
|
||||
withdrawSig: string;
|
||||
coinEv: string;
|
||||
mintBaseUrl: string;
|
||||
coinValue: AmountJson_interface;
|
||||
coinValue: AmountJson;
|
||||
}
|
||||
|
||||
export interface Coin {
|
||||
@ -56,17 +56,18 @@ export interface Coin {
|
||||
coinPriv: string;
|
||||
denomPub: string;
|
||||
denomSig: string;
|
||||
currentAmount: AmountJson_interface;
|
||||
currentAmount: AmountJson;
|
||||
mintBaseUrl: string;
|
||||
}
|
||||
|
||||
|
||||
export interface AmountJson_interface {
|
||||
export interface AmountJson {
|
||||
value: number;
|
||||
fraction: number
|
||||
currency: string;
|
||||
}
|
||||
|
||||
|
||||
export interface ConfirmReserveRequest {
|
||||
/**
|
||||
* Name of the form field for the amount.
|
||||
|
@ -22,7 +22,6 @@
|
||||
*/
|
||||
|
||||
import {Amount} from "./emscriptif"
|
||||
import {AmountJson_interface} from "./types";
|
||||
import {CoinWithDenom} from "./types";
|
||||
import {DepositRequestPS_Args} from "./emscriptif";
|
||||
import {HashCode} from "./emscriptif";
|
||||
@ -45,46 +44,25 @@ import {PreCoin} from "./types";
|
||||
import {rsaUnblind} from "./emscriptif";
|
||||
import {RsaSignature} from "./emscriptif";
|
||||
import {Mint} from "./types";
|
||||
import {Checkable} from "./checkable";
|
||||
import {HttpResponse} from "./http";
|
||||
import {RequestException} from "./http";
|
||||
import {Query} from "./query";
|
||||
import {AmountJson} from "./types";
|
||||
|
||||
"use strict";
|
||||
|
||||
@Checkable.Class
|
||||
class AmountJson {
|
||||
@Checkable.Number
|
||||
value: number;
|
||||
|
||||
@Checkable.Number
|
||||
fraction: number;
|
||||
|
||||
@Checkable.String
|
||||
currency: string;
|
||||
|
||||
static check: (v: any) => AmountJson;
|
||||
}
|
||||
|
||||
|
||||
@Checkable.Class
|
||||
class CoinPaySig {
|
||||
@Checkable.String
|
||||
coin_sig: string;
|
||||
|
||||
@Checkable.String
|
||||
coin_pub: string;
|
||||
|
||||
@Checkable.String
|
||||
ub_sig: string;
|
||||
|
||||
@Checkable.String
|
||||
denom_pub: string;
|
||||
|
||||
@Checkable.Value(AmountJson)
|
||||
f: AmountJson;
|
||||
|
||||
static check: (v: any) => CoinPaySig;
|
||||
}
|
||||
|
||||
|
||||
@ -104,17 +82,17 @@ interface MintInfo {
|
||||
|
||||
interface Offer {
|
||||
contract: Contract;
|
||||
sig: string;
|
||||
merchant_sig: string;
|
||||
H_contract: string;
|
||||
}
|
||||
|
||||
interface Contract {
|
||||
H_wire: string;
|
||||
amount: AmountJson_interface;
|
||||
amount: AmountJson;
|
||||
auditors: string[];
|
||||
expiry: string,
|
||||
locations: string[];
|
||||
max_fee: AmountJson_interface;
|
||||
max_fee: AmountJson;
|
||||
merchant: any;
|
||||
merchant_pub: string;
|
||||
mints: MintInfo[];
|
||||
@ -122,6 +100,7 @@ interface Contract {
|
||||
refund_deadline: string;
|
||||
timestamp: string;
|
||||
transaction_id: number;
|
||||
fulfillment_url: string;
|
||||
}
|
||||
|
||||
|
||||
@ -130,7 +109,7 @@ interface CoinPaySig_interface {
|
||||
coin_pub: string;
|
||||
ub_sig: string;
|
||||
denom_pub: string;
|
||||
f: AmountJson_interface;
|
||||
f: AmountJson;
|
||||
}
|
||||
|
||||
|
||||
@ -177,7 +156,7 @@ function canonicalizeBaseUrl(url) {
|
||||
return x.href()
|
||||
}
|
||||
|
||||
function parsePrettyAmount(pretty: string): AmountJson_interface {
|
||||
function parsePrettyAmount(pretty: string): AmountJson {
|
||||
const res = /([0-9]+)(.[0-9]+)?\s*(\w+)/.exec(pretty);
|
||||
if (!res) {
|
||||
return null;
|
||||
@ -291,8 +270,8 @@ export class Wallet {
|
||||
* @param depositFeeLimit
|
||||
* @param allowedMints
|
||||
*/
|
||||
getPossibleMintCoins(paymentAmount: AmountJson_interface,
|
||||
depositFeeLimit: AmountJson_interface,
|
||||
getPossibleMintCoins(paymentAmount: AmountJson,
|
||||
depositFeeLimit: AmountJson,
|
||||
allowedMints: MintInfo[]): Promise<MintCoins> {
|
||||
|
||||
|
||||
@ -366,15 +345,17 @@ export class Wallet {
|
||||
|
||||
executePay(offer: Offer,
|
||||
payCoinInfo: PayCoinInfo,
|
||||
chosenMint: string): Promise<void> {
|
||||
chosenMint: string): Promise<any> {
|
||||
let payReq = {};
|
||||
payReq["H_wire"] = offer.contract.H_wire;
|
||||
payReq["H_contract"] = offer.H_contract;
|
||||
payReq["transaction_id"] = offer.contract.transaction_id;
|
||||
payReq["refund_deadline"] = offer.contract.refund_deadline;
|
||||
payReq["mint"] = URI(chosenMint).href();
|
||||
payReq["amount"] = offer.contract.amount;
|
||||
payReq["coins"] = payCoinInfo.map((x) => x.sig);
|
||||
payReq["H_contract"] = offer.H_contract;
|
||||
payReq["max_fee"] = offer.contract.max_fee;
|
||||
payReq["merchant_sig"] = offer.merchant_sig;
|
||||
payReq["mint"] = URI(chosenMint).href();
|
||||
payReq["refund_deadline"] = offer.contract.refund_deadline;
|
||||
payReq["timestamp"] = offer.contract.timestamp;
|
||||
payReq["transaction_id"] = offer.contract.transaction_id;
|
||||
let t: Transaction = {
|
||||
contractHash: offer.H_contract,
|
||||
contract: offer.contract,
|
||||
@ -387,7 +368,8 @@ export class Wallet {
|
||||
detail: {
|
||||
merchantName: offer.contract.merchant.name,
|
||||
amount: offer.contract.amount,
|
||||
contractHash: offer.H_contract
|
||||
contractHash: offer.H_contract,
|
||||
fulfillmentUrl: offer.contract.fulfillment_url
|
||||
}
|
||||
};
|
||||
|
||||
@ -395,7 +377,12 @@ export class Wallet {
|
||||
.put("transactions", t)
|
||||
.put("history", historyEntry)
|
||||
.putAll("coins", payCoinInfo.map((pci) => pci.updatedCoin))
|
||||
.finish();
|
||||
.finish()
|
||||
.then(() => {
|
||||
return {
|
||||
success: true
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
confirmPay(offer: Offer): Promise<any> {
|
||||
@ -405,23 +392,31 @@ export class Wallet {
|
||||
offer.contract.mints)
|
||||
}).then((mcs) => {
|
||||
if (Object.keys(mcs).length == 0) {
|
||||
throw Error("Not enough coins.");
|
||||
return {
|
||||
success: false,
|
||||
message: "Not enough coins",
|
||||
};
|
||||
}
|
||||
let mintUrl = Object.keys(mcs)[0];
|
||||
let ds = Wallet.signDeposit(offer, mcs[mintUrl]);
|
||||
return this.executePay(offer, ds, mintUrl);
|
||||
return this
|
||||
.executePay(offer, ds, mintUrl);
|
||||
});
|
||||
}
|
||||
|
||||
doPayment(H_contract): Promise<PaymentResponse> {
|
||||
doPayment(H_contract): Promise<any> {
|
||||
return Promise.resolve().then(() => {
|
||||
return Query(this.db)
|
||||
.get("transactions", H_contract)
|
||||
.then((t) => {
|
||||
if (!t) {
|
||||
throw Error("contract not found");
|
||||
return {
|
||||
success: false,
|
||||
contractFound: false,
|
||||
}
|
||||
let resp: PaymentResponse = {
|
||||
}
|
||||
let resp = {
|
||||
success: true,
|
||||
payReq: t.payReq,
|
||||
contract: t.contract,
|
||||
};
|
||||
@ -682,8 +677,10 @@ export class Wallet {
|
||||
let next = () => {
|
||||
if (workList.length == 0) {
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
let d = workList.pop();
|
||||
console.log("withdrawing", JSON.stringify(d));
|
||||
this.withdraw(d, reserve)
|
||||
.then(() => next())
|
||||
.catch((e) => {
|
||||
@ -760,7 +757,7 @@ export class Wallet {
|
||||
|
||||
getBalances(): Promise<any> {
|
||||
function collectBalances(c: Coin, byCurrency) {
|
||||
let acc: AmountJson_interface = byCurrency[c.currentAmount.currency];
|
||||
let acc: AmountJson = byCurrency[c.currentAmount.currency];
|
||||
if (!acc) {
|
||||
acc = Amount.getZero(c.currentAmount.currency).toJson();
|
||||
}
|
||||
|
@ -66,8 +66,8 @@ System.register(["./wallet", "./db", "./http"], function(exports_1) {
|
||||
},
|
||||
_a["confirm-pay"] = function (db, detail, sendResponse) {
|
||||
wallet.confirmPay(detail.offer, detail.merchantPageUrl)
|
||||
.then(function () {
|
||||
sendResponse({ success: true });
|
||||
.then(function (r) {
|
||||
sendResponse(r);
|
||||
})
|
||||
.catch(function (e) {
|
||||
console.error("exception during 'confirm-pay'");
|
||||
@ -79,11 +79,7 @@ System.register(["./wallet", "./db", "./http"], function(exports_1) {
|
||||
_a["execute-payment"] = function (db, detail, sendResponse) {
|
||||
wallet.doPayment(detail.H_contract)
|
||||
.then(function (r) {
|
||||
sendResponse({
|
||||
success: true,
|
||||
payReq: r.payReq,
|
||||
contract: r.contract,
|
||||
});
|
||||
sendResponse(r);
|
||||
})
|
||||
.catch(function (e) {
|
||||
console.error("exception during 'execute-payment'");
|
||||
|
@ -83,8 +83,8 @@ function makeHandlers(wallet) {
|
||||
},
|
||||
["confirm-pay"]: function(db, detail, sendResponse) {
|
||||
wallet.confirmPay(detail.offer, detail.merchantPageUrl)
|
||||
.then(() => {
|
||||
sendResponse({success: true})
|
||||
.then((r) => {
|
||||
sendResponse(r)
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error("exception during 'confirm-pay'");
|
||||
@ -96,11 +96,7 @@ function makeHandlers(wallet) {
|
||||
["execute-payment"]: function(db, detail, sendResponse) {
|
||||
wallet.doPayment(detail.H_contract)
|
||||
.then((r) => {
|
||||
sendResponse({
|
||||
success: true,
|
||||
payReq: r.payReq,
|
||||
contract: r.contract,
|
||||
});
|
||||
sendResponse(r);
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error("exception during 'execute-payment'");
|
||||
|
@ -14,8 +14,8 @@
|
||||
TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
export function substituteFulfillmentUrl(url: string, offer) {
|
||||
url = url.replace("${H_contract}", offer.H_contract);
|
||||
export function substituteFulfillmentUrl(url: string, vars) {
|
||||
url = url.replace("${H_contract}", vars.H_contract);
|
||||
url = url.replace("${$}", "$");
|
||||
return url;
|
||||
}
|
@ -42,7 +42,6 @@
|
||||
"background": {
|
||||
"scripts": [
|
||||
"lib/vendor/URI.js",
|
||||
"lib/vendor/handlebars-v4.0.5.js",
|
||||
"lib/emscripten/libwrapper.js",
|
||||
"lib/vendor/system-csp-production.src.js",
|
||||
"background/main.js"
|
||||
|
@ -11,23 +11,6 @@
|
||||
<script src="../lib/module-trampoline.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="../style/wallet.css">
|
||||
|
||||
<script id="contract-template" type="text/x-handlebars-template">
|
||||
|
||||
Your contract includes these products:
|
||||
<ul>
|
||||
{{#each products}}
|
||||
<li>{{description}}: {{prettyAmount price}}</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
|
||||
<p />
|
||||
</script>
|
||||
|
||||
<script id="error-template" type="text/x-handlebars-template">
|
||||
Payment was not successful: {{error}}
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<header>
|
||||
<div id="logo"></div>
|
||||
|
@ -27,13 +27,15 @@ System.register(["../lib/web-common"], function(exports_1) {
|
||||
var offer = JSON.parse(query.offer);
|
||||
console.dir(offer);
|
||||
var contract = offer.contract;
|
||||
var error = null;
|
||||
var Contract = {
|
||||
view: function (ctrl) {
|
||||
return [
|
||||
m("p", (_a = ["Hello, this is the wallet. The merchant \"", "\"\n wants to enter a contract over ", "\n with you."], _a.raw = ["Hello, this is the wallet. The merchant \"", "\"\n wants to enter a contract over ", "\n with you."], i18n(_a, contract.merchant.name, prettyAmount(contract.amount)))),
|
||||
m("p", (_b = ["The contract contains the following products:"], _b.raw = ["The contract contains the following products:"], i18n(_b))),
|
||||
m('ul', _.map(contract.products, function (p) { return m("li", p.description + ": " + prettyAmount(p.price)); })),
|
||||
m("button", { onclick: doPayment }, (_c = ["Confirm Payment"], _c.raw = ["Confirm Payment"], i18n(_c)))
|
||||
m("button", { onclick: doPayment }, (_c = ["Confirm Payment"], _c.raw = ["Confirm Payment"], i18n(_c))),
|
||||
m("p", error ? error : []),
|
||||
];
|
||||
var _a, _b, _c;
|
||||
}
|
||||
@ -46,6 +48,8 @@ System.register(["../lib/web-common"], function(exports_1) {
|
||||
chrome.runtime.sendMessage({ type: 'confirm-pay', detail: d }, function (resp) {
|
||||
if (!resp.success) {
|
||||
console.log("confirm-pay error", JSON.stringify(resp));
|
||||
error = resp.message;
|
||||
m.redraw();
|
||||
return;
|
||||
}
|
||||
var c = d.offer.contract;
|
||||
|
@ -33,6 +33,7 @@ export function main() {
|
||||
let offer = JSON.parse(query.offer);
|
||||
console.dir(offer);
|
||||
let contract = offer.contract;
|
||||
let error = null;
|
||||
|
||||
var Contract = {
|
||||
view(ctrl) {
|
||||
@ -47,7 +48,8 @@ export function main() {
|
||||
_.map(contract.products,
|
||||
(p: any) => m("li",
|
||||
`${p.description}: ${prettyAmount(p.price)}`))),
|
||||
m("button", {onclick: doPayment}, i18n`Confirm Payment`)
|
||||
m("button", {onclick: doPayment}, i18n`Confirm Payment`),
|
||||
m("p", error ? error : []),
|
||||
];
|
||||
}
|
||||
};
|
||||
@ -62,6 +64,8 @@ export function main() {
|
||||
chrome.runtime.sendMessage({type: 'confirm-pay', detail: d}, (resp) => {
|
||||
if (!resp.success) {
|
||||
console.log("confirm-pay error", JSON.stringify(resp));
|
||||
error = resp.message;
|
||||
m.redraw();
|
||||
return;
|
||||
}
|
||||
let c = d.offer.contract;
|
||||
|
@ -8,13 +8,13 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2016-01-27 01:05+0100\n"
|
||||
"POT-Creation-Date: 2016-01-27 01:51+0100\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"Language: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=CHARSET\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: example/test.ts:3
|
||||
@ -95,3 +95,13 @@ msgid ""
|
||||
"asdf"
|
||||
msgstr ""
|
||||
|
||||
#: example/test.ts:42
|
||||
#, csharp-format
|
||||
msgid "This message appears twice"
|
||||
msgstr ""
|
||||
|
||||
#: example/test.ts:45
|
||||
#, csharp-format
|
||||
msgid "This message appears twice"
|
||||
msgstr ""
|
||||
|
||||
|
@ -18,7 +18,11 @@ It has multiple lines, and a trailing empty line.
|
||||
|
||||
*/
|
||||
console.log(/*lol*/i18n.foo`Hello7,${123} World${42}`);
|
||||
console.log(i18n.foo`${"foo"}Hello8,${123} World${42}`);
|
||||
|
||||
|
||||
i18n.plural()
|
||||
|
||||
console.log(i18n`${"foo"}Hello8,${123} World${42}`);
|
||||
|
||||
/*
|
||||
|
||||
@ -40,3 +44,10 @@ it should be wrapped and stuff`);
|
||||
|
||||
// This is a single line comment
|
||||
console.log(i18n`Hello12 this is a long long string it will go over multiple lines and in the pofile it should be wrapped and stuff. asdf asdf asdf asdf asdf asdf asdf asdf adsf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf`);
|
||||
|
||||
|
||||
|
||||
// First occurence
|
||||
console.log(i18n`This message appears twice`);
|
||||
// Second occurence
|
||||
console.log(i18n`This message appears twice`);
|
||||
|
@ -20,6 +20,8 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
import {substituteFulfillmentUrl} from "../lib/web-common";
|
||||
|
||||
declare var m: any;
|
||||
declare var i18n: any;
|
||||
|
||||
@ -106,11 +108,22 @@ function formatAmount(amount) {
|
||||
return `${v.toFixed(2)} ${amount.currency}`;
|
||||
}
|
||||
|
||||
|
||||
function abbrevKey(s: string) {
|
||||
return m("span.abbrev", {title: s}, (s.slice(0, 5) + ".."))
|
||||
}
|
||||
|
||||
|
||||
function retryPayment(url, contractHash) {
|
||||
return function() {
|
||||
chrome.tabs.create({
|
||||
"url": substituteFulfillmentUrl(url,
|
||||
{H_contract: contractHash})
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function formatHistoryItem(historyItem) {
|
||||
const d = historyItem.detail;
|
||||
const t = historyItem.timestamp;
|
||||
@ -124,10 +137,14 @@ function formatHistoryItem(historyItem) {
|
||||
return m("p",
|
||||
i18n`Withdraw at ${formatTimestamp(t)}`);
|
||||
case "pay":
|
||||
let url = substituteFulfillmentUrl(d.fulfillmentUrl,
|
||||
{H_contract: d.contractHash});
|
||||
return m("p",
|
||||
[
|
||||
i18n`Payment for ${formatAmount(d.amount)} to merchant ${d.merchantName}. `,
|
||||
m("a[href=javascript:;]", "Retry")
|
||||
m(`a`,
|
||||
{href: url, onclick: openTab(url)},
|
||||
"Retry")
|
||||
]);
|
||||
default:
|
||||
return m("p", i18n`Unknown event (${historyItem.type})`);
|
||||
@ -204,3 +221,12 @@ function openExtensionPage(page) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function openTab(page) {
|
||||
return function() {
|
||||
chrome.tabs.create({
|
||||
"url": page
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,6 @@
|
||||
"lib/i18n.ts",
|
||||
"lib/refs.ts",
|
||||
"lib/web-common.ts",
|
||||
"lib/wallet/checkable.ts",
|
||||
"lib/wallet/db.ts",
|
||||
"lib/wallet/emscriptif.ts",
|
||||
"lib/wallet/http.ts",
|
||||
|
Loading…
Reference in New Issue
Block a user