new fulfillment protocol
This commit is contained in:
parent
b150470eb6
commit
42a0076f59
@ -17,19 +17,22 @@
|
|||||||
// query the availability of Taler.
|
// query the availability of Taler.
|
||||||
/// <reference path="../lib/decl/chrome/chrome.d.ts" />
|
/// <reference path="../lib/decl/chrome/chrome.d.ts" />
|
||||||
"use strict";
|
"use strict";
|
||||||
|
// Make sure we don't pollute the namespace too much.
|
||||||
|
var TalerNotify;
|
||||||
|
(function (TalerNotify) {
|
||||||
console.log("Taler injected");
|
console.log("Taler injected");
|
||||||
function subst(url, H_contract) {
|
function subst(url, H_contract) {
|
||||||
url = url.replace("${H_contract}", H_contract);
|
url = url.replace("${H_contract}", H_contract);
|
||||||
url = url.replace("${$}", "$");
|
url = url.replace("${$}", "$");
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
var $ = function (x) { return document.getElementById(x); };
|
||||||
document.addEventListener("taler-probe", function (e) {
|
document.addEventListener("taler-probe", function (e) {
|
||||||
var evt = new Event("taler-wallet-present");
|
var evt = new Event("taler-wallet-present");
|
||||||
document.dispatchEvent(evt);
|
document.dispatchEvent(evt);
|
||||||
console.log("handshake done");
|
console.log("handshake done");
|
||||||
});
|
});
|
||||||
document.addEventListener("taler-create-reserve", function (e) {
|
document.addEventListener("taler-create-reserve", function (e) {
|
||||||
var $ = function (x) { return document.getElementById(x); };
|
|
||||||
console.log("taler-create-reserve with " + JSON.stringify(e.detail));
|
console.log("taler-create-reserve with " + JSON.stringify(e.detail));
|
||||||
var form_uri = $(e.detail.form_id).action;
|
var form_uri = $(e.detail.form_id).action;
|
||||||
// TODO: validate event fields
|
// TODO: validate event fields
|
||||||
@ -54,7 +57,6 @@ document.addEventListener("taler-contract", function (e) {
|
|||||||
var params = {
|
var params = {
|
||||||
offer: JSON.stringify(offer),
|
offer: JSON.stringify(offer),
|
||||||
merchantPageUrl: document.location.href,
|
merchantPageUrl: document.location.href,
|
||||||
cookie: document.cookie,
|
|
||||||
};
|
};
|
||||||
document.location.href = uri.query(params).href();
|
document.location.href = uri.query(params).href();
|
||||||
});
|
});
|
||||||
@ -72,26 +74,34 @@ document.addEventListener('taler-execute-payment', function (e) {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
chrome.runtime.sendMessage(msg, function (resp) {
|
chrome.runtime.sendMessage(msg, function (resp) {
|
||||||
|
console.log("got resp");
|
||||||
|
console.dir(resp);
|
||||||
if (!resp.success) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
var contract = resp.contract;
|
var contract = resp.contract;
|
||||||
if (!contract) {
|
if (!contract) {
|
||||||
throw Error("contract missing");
|
throw Error("contract missing");
|
||||||
}
|
}
|
||||||
var payReq = Object.assign({}, resp.payReq);
|
|
||||||
if (e.detail.require_contract) {
|
|
||||||
payReq.contract = contract;
|
|
||||||
}
|
|
||||||
console.log("Making request to ", payUrl);
|
console.log("Making request to ", payUrl);
|
||||||
var r = new XMLHttpRequest();
|
var r = new XMLHttpRequest();
|
||||||
r.open('post', payUrl);
|
r.open('post', payUrl);
|
||||||
r.send(JSON.stringify(payReq));
|
r.send(JSON.stringify(resp.payReq));
|
||||||
r.onload = function () {
|
r.onload = function () {
|
||||||
switch (r.status) {
|
switch (r.status) {
|
||||||
case 200:
|
case 200:
|
||||||
console.log("going to", contract.fulfillment_url);
|
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.href = subst(contract.fulfillment_url, e.detail.H_contract);
|
||||||
window.location.reload(true);
|
window.location.reload(true);
|
||||||
break;
|
break;
|
||||||
@ -102,4 +112,5 @@ document.addEventListener('taler-execute-payment', function (e) {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
})(TalerNotify || (TalerNotify = {}));
|
||||||
//# sourceMappingURL=notify.js.map
|
//# sourceMappingURL=notify.js.map
|
@ -21,6 +21,9 @@
|
|||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
|
||||||
|
// Make sure we don't pollute the namespace too much.
|
||||||
|
namespace TalerNotify {
|
||||||
console.log("Taler injected");
|
console.log("Taler injected");
|
||||||
|
|
||||||
function subst(url: string, H_contract) {
|
function subst(url: string, H_contract) {
|
||||||
@ -29,6 +32,7 @@ function subst(url: string, H_contract) {
|
|||||||
return url;
|
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");
|
let evt = new Event("taler-wallet-present");
|
||||||
@ -37,7 +41,6 @@ document.addEventListener("taler-probe", function(e) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
document.addEventListener("taler-create-reserve", function(e: CustomEvent) {
|
document.addEventListener("taler-create-reserve", function(e: CustomEvent) {
|
||||||
let $ = (x) => document.getElementById(x);
|
|
||||||
console.log("taler-create-reserve with " + JSON.stringify(e.detail));
|
console.log("taler-create-reserve with " + JSON.stringify(e.detail));
|
||||||
let form_uri = (<HTMLFormElement>$(e.detail.form_id)).action;
|
let form_uri = (<HTMLFormElement>$(e.detail.form_id)).action;
|
||||||
// TODO: validate event fields
|
// TODO: validate event fields
|
||||||
@ -64,7 +67,6 @@ document.addEventListener("taler-contract", function(e: CustomEvent) {
|
|||||||
let params = {
|
let params = {
|
||||||
offer: JSON.stringify(offer),
|
offer: JSON.stringify(offer),
|
||||||
merchantPageUrl: document.location.href,
|
merchantPageUrl: document.location.href,
|
||||||
cookie: document.cookie,
|
|
||||||
};
|
};
|
||||||
document.location.href = uri.query(params).href();
|
document.location.href = uri.query(params).href();
|
||||||
});
|
});
|
||||||
@ -84,8 +86,17 @@ document.addEventListener('taler-execute-payment', function(e: CustomEvent) {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
chrome.runtime.sendMessage(msg, (resp) => {
|
chrome.runtime.sendMessage(msg, (resp) => {
|
||||||
|
console.log("got resp");
|
||||||
|
console.dir(resp);
|
||||||
if (!resp.success) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
let contract = resp.contract;
|
let contract = resp.contract;
|
||||||
@ -93,19 +104,16 @@ document.addEventListener('taler-execute-payment', function(e: CustomEvent) {
|
|||||||
throw Error("contract missing");
|
throw Error("contract missing");
|
||||||
}
|
}
|
||||||
|
|
||||||
let payReq = Object.assign({}, resp.payReq);
|
|
||||||
if (e.detail.require_contract) {
|
|
||||||
payReq.contract = contract;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log("Making request to ", payUrl);
|
console.log("Making request to ", payUrl);
|
||||||
let r = new XMLHttpRequest();
|
let r = new XMLHttpRequest();
|
||||||
r.open('post', payUrl);
|
r.open('post', payUrl);
|
||||||
r.send(JSON.stringify(payReq));
|
r.send(JSON.stringify(resp.payReq));
|
||||||
r.onload = () => {
|
r.onload = () => {
|
||||||
switch (r.status) {
|
switch (r.status) {
|
||||||
case 200:
|
case 200:
|
||||||
console.log("going to", contract.fulfillment_url);
|
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,
|
window.location.href = subst(contract.fulfillment_url,
|
||||||
e.detail.H_contract);
|
e.detail.H_contract);
|
||||||
window.location.reload(true);
|
window.location.reload(true);
|
||||||
@ -117,3 +125,4 @@ 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/>
|
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";
|
import * as EmscWrapper from "../emscripten/emsc";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -288,7 +288,7 @@ arenaStack.push(new SyncArena());
|
|||||||
|
|
||||||
|
|
||||||
export class Amount extends ArenaObject {
|
export class Amount extends ArenaObject {
|
||||||
constructor(args?: AmountJson_interface, arena?: Arena) {
|
constructor(args?: AmountJson, arena?: Arena) {
|
||||||
super(arena);
|
super(arena);
|
||||||
if (args) {
|
if (args) {
|
||||||
this.nativePtr = emscAlloc.get_amount(args.value,
|
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/>
|
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.
|
* Database query abstractions.
|
||||||
|
@ -33,10 +33,10 @@ export interface Keys {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface Denomination {
|
export interface Denomination {
|
||||||
value: AmountJson_interface;
|
value: AmountJson;
|
||||||
denom_pub: string;
|
denom_pub: string;
|
||||||
fee_withdraw: AmountJson_interface;
|
fee_withdraw: AmountJson;
|
||||||
fee_deposit: AmountJson_interface;
|
fee_deposit: AmountJson;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PreCoin {
|
export interface PreCoin {
|
||||||
@ -48,7 +48,7 @@ export interface PreCoin {
|
|||||||
withdrawSig: string;
|
withdrawSig: string;
|
||||||
coinEv: string;
|
coinEv: string;
|
||||||
mintBaseUrl: string;
|
mintBaseUrl: string;
|
||||||
coinValue: AmountJson_interface;
|
coinValue: AmountJson;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Coin {
|
export interface Coin {
|
||||||
@ -56,17 +56,18 @@ export interface Coin {
|
|||||||
coinPriv: string;
|
coinPriv: string;
|
||||||
denomPub: string;
|
denomPub: string;
|
||||||
denomSig: string;
|
denomSig: string;
|
||||||
currentAmount: AmountJson_interface;
|
currentAmount: AmountJson;
|
||||||
mintBaseUrl: string;
|
mintBaseUrl: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export interface AmountJson_interface {
|
export interface AmountJson {
|
||||||
value: number;
|
value: number;
|
||||||
fraction: number
|
fraction: number
|
||||||
currency: string;
|
currency: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export interface ConfirmReserveRequest {
|
export interface ConfirmReserveRequest {
|
||||||
/**
|
/**
|
||||||
* Name of the form field for the amount.
|
* Name of the form field for the amount.
|
||||||
|
@ -22,7 +22,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {Amount} from "./emscriptif"
|
import {Amount} from "./emscriptif"
|
||||||
import {AmountJson_interface} from "./types";
|
|
||||||
import {CoinWithDenom} from "./types";
|
import {CoinWithDenom} from "./types";
|
||||||
import {DepositRequestPS_Args} from "./emscriptif";
|
import {DepositRequestPS_Args} from "./emscriptif";
|
||||||
import {HashCode} from "./emscriptif";
|
import {HashCode} from "./emscriptif";
|
||||||
@ -45,46 +44,25 @@ import {PreCoin} from "./types";
|
|||||||
import {rsaUnblind} from "./emscriptif";
|
import {rsaUnblind} from "./emscriptif";
|
||||||
import {RsaSignature} from "./emscriptif";
|
import {RsaSignature} from "./emscriptif";
|
||||||
import {Mint} from "./types";
|
import {Mint} from "./types";
|
||||||
import {Checkable} from "./checkable";
|
|
||||||
import {HttpResponse} from "./http";
|
import {HttpResponse} from "./http";
|
||||||
import {RequestException} from "./http";
|
import {RequestException} from "./http";
|
||||||
import {Query} from "./query";
|
import {Query} from "./query";
|
||||||
|
import {AmountJson} from "./types";
|
||||||
|
|
||||||
"use strict";
|
"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 {
|
class CoinPaySig {
|
||||||
@Checkable.String
|
|
||||||
coin_sig: string;
|
coin_sig: string;
|
||||||
|
|
||||||
@Checkable.String
|
|
||||||
coin_pub: string;
|
coin_pub: string;
|
||||||
|
|
||||||
@Checkable.String
|
|
||||||
ub_sig: string;
|
ub_sig: string;
|
||||||
|
|
||||||
@Checkable.String
|
|
||||||
denom_pub: string;
|
denom_pub: string;
|
||||||
|
|
||||||
@Checkable.Value(AmountJson)
|
|
||||||
f: AmountJson;
|
f: AmountJson;
|
||||||
|
|
||||||
static check: (v: any) => CoinPaySig;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -104,17 +82,17 @@ interface MintInfo {
|
|||||||
|
|
||||||
interface Offer {
|
interface Offer {
|
||||||
contract: Contract;
|
contract: Contract;
|
||||||
sig: string;
|
merchant_sig: string;
|
||||||
H_contract: string;
|
H_contract: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Contract {
|
interface Contract {
|
||||||
H_wire: string;
|
H_wire: string;
|
||||||
amount: AmountJson_interface;
|
amount: AmountJson;
|
||||||
auditors: string[];
|
auditors: string[];
|
||||||
expiry: string,
|
expiry: string,
|
||||||
locations: string[];
|
locations: string[];
|
||||||
max_fee: AmountJson_interface;
|
max_fee: AmountJson;
|
||||||
merchant: any;
|
merchant: any;
|
||||||
merchant_pub: string;
|
merchant_pub: string;
|
||||||
mints: MintInfo[];
|
mints: MintInfo[];
|
||||||
@ -122,6 +100,7 @@ interface Contract {
|
|||||||
refund_deadline: string;
|
refund_deadline: string;
|
||||||
timestamp: string;
|
timestamp: string;
|
||||||
transaction_id: number;
|
transaction_id: number;
|
||||||
|
fulfillment_url: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -130,7 +109,7 @@ interface CoinPaySig_interface {
|
|||||||
coin_pub: string;
|
coin_pub: string;
|
||||||
ub_sig: string;
|
ub_sig: string;
|
||||||
denom_pub: string;
|
denom_pub: string;
|
||||||
f: AmountJson_interface;
|
f: AmountJson;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -177,7 +156,7 @@ function canonicalizeBaseUrl(url) {
|
|||||||
return x.href()
|
return x.href()
|
||||||
}
|
}
|
||||||
|
|
||||||
function parsePrettyAmount(pretty: string): AmountJson_interface {
|
function parsePrettyAmount(pretty: string): AmountJson {
|
||||||
const res = /([0-9]+)(.[0-9]+)?\s*(\w+)/.exec(pretty);
|
const res = /([0-9]+)(.[0-9]+)?\s*(\w+)/.exec(pretty);
|
||||||
if (!res) {
|
if (!res) {
|
||||||
return null;
|
return null;
|
||||||
@ -291,8 +270,8 @@ export class Wallet {
|
|||||||
* @param depositFeeLimit
|
* @param depositFeeLimit
|
||||||
* @param allowedMints
|
* @param allowedMints
|
||||||
*/
|
*/
|
||||||
getPossibleMintCoins(paymentAmount: AmountJson_interface,
|
getPossibleMintCoins(paymentAmount: AmountJson,
|
||||||
depositFeeLimit: AmountJson_interface,
|
depositFeeLimit: AmountJson,
|
||||||
allowedMints: MintInfo[]): Promise<MintCoins> {
|
allowedMints: MintInfo[]): Promise<MintCoins> {
|
||||||
|
|
||||||
|
|
||||||
@ -366,15 +345,17 @@ export class Wallet {
|
|||||||
|
|
||||||
executePay(offer: Offer,
|
executePay(offer: Offer,
|
||||||
payCoinInfo: PayCoinInfo,
|
payCoinInfo: PayCoinInfo,
|
||||||
chosenMint: string): Promise<void> {
|
chosenMint: string): Promise<any> {
|
||||||
let payReq = {};
|
let payReq = {};
|
||||||
payReq["H_wire"] = offer.contract.H_wire;
|
payReq["amount"] = offer.contract.amount;
|
||||||
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["coins"] = payCoinInfo.map((x) => x.sig);
|
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["timestamp"] = offer.contract.timestamp;
|
||||||
|
payReq["transaction_id"] = offer.contract.transaction_id;
|
||||||
let t: Transaction = {
|
let t: Transaction = {
|
||||||
contractHash: offer.H_contract,
|
contractHash: offer.H_contract,
|
||||||
contract: offer.contract,
|
contract: offer.contract,
|
||||||
@ -387,7 +368,8 @@ export class Wallet {
|
|||||||
detail: {
|
detail: {
|
||||||
merchantName: offer.contract.merchant.name,
|
merchantName: offer.contract.merchant.name,
|
||||||
amount: offer.contract.amount,
|
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("transactions", t)
|
||||||
.put("history", historyEntry)
|
.put("history", historyEntry)
|
||||||
.putAll("coins", payCoinInfo.map((pci) => pci.updatedCoin))
|
.putAll("coins", payCoinInfo.map((pci) => pci.updatedCoin))
|
||||||
.finish();
|
.finish()
|
||||||
|
.then(() => {
|
||||||
|
return {
|
||||||
|
success: true
|
||||||
|
};
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
confirmPay(offer: Offer): Promise<any> {
|
confirmPay(offer: Offer): Promise<any> {
|
||||||
@ -405,23 +392,31 @@ export class Wallet {
|
|||||||
offer.contract.mints)
|
offer.contract.mints)
|
||||||
}).then((mcs) => {
|
}).then((mcs) => {
|
||||||
if (Object.keys(mcs).length == 0) {
|
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 mintUrl = Object.keys(mcs)[0];
|
||||||
let ds = Wallet.signDeposit(offer, mcs[mintUrl]);
|
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 Promise.resolve().then(() => {
|
||||||
return Query(this.db)
|
return Query(this.db)
|
||||||
.get("transactions", H_contract)
|
.get("transactions", H_contract)
|
||||||
.then((t) => {
|
.then((t) => {
|
||||||
if (!t) {
|
if (!t) {
|
||||||
throw Error("contract not found");
|
return {
|
||||||
|
success: false,
|
||||||
|
contractFound: false,
|
||||||
}
|
}
|
||||||
let resp: PaymentResponse = {
|
}
|
||||||
|
let resp = {
|
||||||
|
success: true,
|
||||||
payReq: t.payReq,
|
payReq: t.payReq,
|
||||||
contract: t.contract,
|
contract: t.contract,
|
||||||
};
|
};
|
||||||
@ -682,8 +677,10 @@ export class Wallet {
|
|||||||
let next = () => {
|
let next = () => {
|
||||||
if (workList.length == 0) {
|
if (workList.length == 0) {
|
||||||
resolve();
|
resolve();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
let d = workList.pop();
|
let d = workList.pop();
|
||||||
|
console.log("withdrawing", JSON.stringify(d));
|
||||||
this.withdraw(d, reserve)
|
this.withdraw(d, reserve)
|
||||||
.then(() => next())
|
.then(() => next())
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
@ -760,7 +757,7 @@ export class Wallet {
|
|||||||
|
|
||||||
getBalances(): Promise<any> {
|
getBalances(): Promise<any> {
|
||||||
function collectBalances(c: Coin, byCurrency) {
|
function collectBalances(c: Coin, byCurrency) {
|
||||||
let acc: AmountJson_interface = byCurrency[c.currentAmount.currency];
|
let acc: AmountJson = byCurrency[c.currentAmount.currency];
|
||||||
if (!acc) {
|
if (!acc) {
|
||||||
acc = Amount.getZero(c.currentAmount.currency).toJson();
|
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) {
|
_a["confirm-pay"] = function (db, detail, sendResponse) {
|
||||||
wallet.confirmPay(detail.offer, detail.merchantPageUrl)
|
wallet.confirmPay(detail.offer, detail.merchantPageUrl)
|
||||||
.then(function () {
|
.then(function (r) {
|
||||||
sendResponse({ success: true });
|
sendResponse(r);
|
||||||
})
|
})
|
||||||
.catch(function (e) {
|
.catch(function (e) {
|
||||||
console.error("exception during 'confirm-pay'");
|
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) {
|
_a["execute-payment"] = function (db, detail, sendResponse) {
|
||||||
wallet.doPayment(detail.H_contract)
|
wallet.doPayment(detail.H_contract)
|
||||||
.then(function (r) {
|
.then(function (r) {
|
||||||
sendResponse({
|
sendResponse(r);
|
||||||
success: true,
|
|
||||||
payReq: r.payReq,
|
|
||||||
contract: r.contract,
|
|
||||||
});
|
|
||||||
})
|
})
|
||||||
.catch(function (e) {
|
.catch(function (e) {
|
||||||
console.error("exception during 'execute-payment'");
|
console.error("exception during 'execute-payment'");
|
||||||
|
@ -83,8 +83,8 @@ function makeHandlers(wallet) {
|
|||||||
},
|
},
|
||||||
["confirm-pay"]: function(db, detail, sendResponse) {
|
["confirm-pay"]: function(db, detail, sendResponse) {
|
||||||
wallet.confirmPay(detail.offer, detail.merchantPageUrl)
|
wallet.confirmPay(detail.offer, detail.merchantPageUrl)
|
||||||
.then(() => {
|
.then((r) => {
|
||||||
sendResponse({success: true})
|
sendResponse(r)
|
||||||
})
|
})
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
console.error("exception during 'confirm-pay'");
|
console.error("exception during 'confirm-pay'");
|
||||||
@ -96,11 +96,7 @@ function makeHandlers(wallet) {
|
|||||||
["execute-payment"]: function(db, detail, sendResponse) {
|
["execute-payment"]: function(db, detail, sendResponse) {
|
||||||
wallet.doPayment(detail.H_contract)
|
wallet.doPayment(detail.H_contract)
|
||||||
.then((r) => {
|
.then((r) => {
|
||||||
sendResponse({
|
sendResponse(r);
|
||||||
success: true,
|
|
||||||
payReq: r.payReq,
|
|
||||||
contract: r.contract,
|
|
||||||
});
|
|
||||||
})
|
})
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
console.error("exception during 'execute-payment'");
|
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/>
|
TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export function substituteFulfillmentUrl(url: string, offer) {
|
export function substituteFulfillmentUrl(url: string, vars) {
|
||||||
url = url.replace("${H_contract}", offer.H_contract);
|
url = url.replace("${H_contract}", vars.H_contract);
|
||||||
url = url.replace("${$}", "$");
|
url = url.replace("${$}", "$");
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
@ -42,7 +42,6 @@
|
|||||||
"background": {
|
"background": {
|
||||||
"scripts": [
|
"scripts": [
|
||||||
"lib/vendor/URI.js",
|
"lib/vendor/URI.js",
|
||||||
"lib/vendor/handlebars-v4.0.5.js",
|
|
||||||
"lib/emscripten/libwrapper.js",
|
"lib/emscripten/libwrapper.js",
|
||||||
"lib/vendor/system-csp-production.src.js",
|
"lib/vendor/system-csp-production.src.js",
|
||||||
"background/main.js"
|
"background/main.js"
|
||||||
|
@ -11,23 +11,6 @@
|
|||||||
<script src="../lib/module-trampoline.js"></script>
|
<script src="../lib/module-trampoline.js"></script>
|
||||||
<link rel="stylesheet" type="text/css" href="../style/wallet.css">
|
<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>
|
<body>
|
||||||
<header>
|
<header>
|
||||||
<div id="logo"></div>
|
<div id="logo"></div>
|
||||||
|
@ -27,13 +27,15 @@ System.register(["../lib/web-common"], function(exports_1) {
|
|||||||
var offer = JSON.parse(query.offer);
|
var offer = JSON.parse(query.offer);
|
||||||
console.dir(offer);
|
console.dir(offer);
|
||||||
var contract = offer.contract;
|
var contract = offer.contract;
|
||||||
|
var error = null;
|
||||||
var Contract = {
|
var Contract = {
|
||||||
view: function (ctrl) {
|
view: function (ctrl) {
|
||||||
return [
|
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", (_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("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('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;
|
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) {
|
chrome.runtime.sendMessage({ type: 'confirm-pay', detail: d }, function (resp) {
|
||||||
if (!resp.success) {
|
if (!resp.success) {
|
||||||
console.log("confirm-pay error", JSON.stringify(resp));
|
console.log("confirm-pay error", JSON.stringify(resp));
|
||||||
|
error = resp.message;
|
||||||
|
m.redraw();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var c = d.offer.contract;
|
var c = d.offer.contract;
|
||||||
|
@ -33,6 +33,7 @@ export function main() {
|
|||||||
let offer = JSON.parse(query.offer);
|
let offer = JSON.parse(query.offer);
|
||||||
console.dir(offer);
|
console.dir(offer);
|
||||||
let contract = offer.contract;
|
let contract = offer.contract;
|
||||||
|
let error = null;
|
||||||
|
|
||||||
var Contract = {
|
var Contract = {
|
||||||
view(ctrl) {
|
view(ctrl) {
|
||||||
@ -47,7 +48,8 @@ export function main() {
|
|||||||
_.map(contract.products,
|
_.map(contract.products,
|
||||||
(p: any) => m("li",
|
(p: any) => m("li",
|
||||||
`${p.description}: ${prettyAmount(p.price)}`))),
|
`${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) => {
|
chrome.runtime.sendMessage({type: 'confirm-pay', detail: d}, (resp) => {
|
||||||
if (!resp.success) {
|
if (!resp.success) {
|
||||||
console.log("confirm-pay error", JSON.stringify(resp));
|
console.log("confirm-pay error", JSON.stringify(resp));
|
||||||
|
error = resp.message;
|
||||||
|
m.redraw();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let c = d.offer.contract;
|
let c = d.offer.contract;
|
||||||
|
@ -8,13 +8,13 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \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"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
"Language: \n"
|
"Language: \n"
|
||||||
"MIME-Version: 1.0\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"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
|
||||||
#: example/test.ts:3
|
#: example/test.ts:3
|
||||||
@ -95,3 +95,13 @@ msgid ""
|
|||||||
"asdf"
|
"asdf"
|
||||||
msgstr ""
|
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(/*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
|
// 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`);
|
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";
|
"use strict";
|
||||||
|
|
||||||
|
import {substituteFulfillmentUrl} from "../lib/web-common";
|
||||||
|
|
||||||
declare var m: any;
|
declare var m: any;
|
||||||
declare var i18n: any;
|
declare var i18n: any;
|
||||||
|
|
||||||
@ -106,11 +108,22 @@ function formatAmount(amount) {
|
|||||||
return `${v.toFixed(2)} ${amount.currency}`;
|
return `${v.toFixed(2)} ${amount.currency}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function abbrevKey(s: string) {
|
function abbrevKey(s: string) {
|
||||||
return m("span.abbrev", {title: s}, (s.slice(0, 5) + ".."))
|
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) {
|
function formatHistoryItem(historyItem) {
|
||||||
const d = historyItem.detail;
|
const d = historyItem.detail;
|
||||||
const t = historyItem.timestamp;
|
const t = historyItem.timestamp;
|
||||||
@ -124,10 +137,14 @@ function formatHistoryItem(historyItem) {
|
|||||||
return m("p",
|
return m("p",
|
||||||
i18n`Withdraw at ${formatTimestamp(t)}`);
|
i18n`Withdraw at ${formatTimestamp(t)}`);
|
||||||
case "pay":
|
case "pay":
|
||||||
|
let url = substituteFulfillmentUrl(d.fulfillmentUrl,
|
||||||
|
{H_contract: d.contractHash});
|
||||||
return m("p",
|
return m("p",
|
||||||
[
|
[
|
||||||
i18n`Payment for ${formatAmount(d.amount)} to merchant ${d.merchantName}. `,
|
i18n`Payment for ${formatAmount(d.amount)} to merchant ${d.merchantName}. `,
|
||||||
m("a[href=javascript:;]", "Retry")
|
m(`a`,
|
||||||
|
{href: url, onclick: openTab(url)},
|
||||||
|
"Retry")
|
||||||
]);
|
]);
|
||||||
default:
|
default:
|
||||||
return m("p", i18n`Unknown event (${historyItem.type})`);
|
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/i18n.ts",
|
||||||
"lib/refs.ts",
|
"lib/refs.ts",
|
||||||
"lib/web-common.ts",
|
"lib/web-common.ts",
|
||||||
"lib/wallet/checkable.ts",
|
|
||||||
"lib/wallet/db.ts",
|
"lib/wallet/db.ts",
|
||||||
"lib/wallet/emscriptif.ts",
|
"lib/wallet/emscriptif.ts",
|
||||||
"lib/wallet/http.ts",
|
"lib/wallet/http.ts",
|
||||||
|
Loading…
Reference in New Issue
Block a user