summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorFlorian Dold <florian.dold@gmail.com>2017-05-28 01:10:54 +0200
committerFlorian Dold <florian.dold@gmail.com>2017-05-28 13:46:36 +0200
commit08bd3dc0e8a3c2370e4e8abbaa241eaafc144f4c (patch)
tree9a55a5734718e7c278ccb24733425184fb8cea34 /src
parent7fff4499fd915bcea3fa93b1aa8b35f4fe7a6027 (diff)
downloadwallet-core-08bd3dc0e8a3c2370e4e8abbaa241eaafc144f4c.tar.gz
wallet-core-08bd3dc0e8a3c2370e4e8abbaa241eaafc144f4c.tar.bz2
wallet-core-08bd3dc0e8a3c2370e4e8abbaa241eaafc144f4c.zip
add linting rules and fix them
Diffstat (limited to 'src')
-rw-r--r--src/checkable.ts146
-rw-r--r--src/chromeBadge.ts39
-rw-r--r--src/components.ts2
-rw-r--r--src/content_scripts/notify.ts155
-rw-r--r--src/crypto/cryptoApi-test.ts126
-rw-r--r--src/crypto/cryptoApi.ts67
-rw-r--r--src/crypto/cryptoWorker.ts214
-rw-r--r--src/crypto/emscInterface-test.ts109
-rw-r--r--src/crypto/emscInterface.ts384
-rw-r--r--src/crypto/emscLoader.d.ts12
-rw-r--r--src/crypto/nodeWorker.ts5
-rw-r--r--src/crypto/nodeWorkerEntry.ts38
-rw-r--r--src/helpers-test.ts19
-rw-r--r--src/helpers.ts28
-rw-r--r--src/http.ts12
-rw-r--r--src/logging.ts96
-rw-r--r--src/pages/show-db.ts34
-rw-r--r--src/query.ts241
-rw-r--r--src/timer.ts2
-rw-r--r--src/types-test.ts75
-rw-r--r--src/types.ts66
-rw-r--r--src/wallet-test.ts93
-rw-r--r--src/wallet.ts842
-rw-r--r--src/wxApi.ts13
-rw-r--r--src/wxBackend.ts263
25 files changed, 1591 insertions, 1490 deletions
diff --git a/src/checkable.ts b/src/checkable.ts
index 1b6e371f6..802d8f32d 100644
--- a/src/checkable.ts
+++ b/src/checkable.ts
@@ -40,7 +40,7 @@
*/
export namespace Checkable {
- type Path = (number | string)[];
+ type Path = Array<number | string>;
interface SchemaErrorConstructor {
new (err: string): SchemaError;
@@ -67,22 +67,22 @@ export namespace Checkable {
props: Prop[];
}
- export let SchemaError = (function SchemaError(this: any, message: string) {
- let that: any = this as any;
- that.name = 'SchemaError';
+ export const SchemaError = (function SchemaError(this: any, message: string) {
+ const that: any = this as any;
+ that.name = "SchemaError";
that.message = message;
- that.stack = (<any>new Error()).stack;
+ that.stack = (new Error() as any).stack;
}) as any as SchemaErrorConstructor;
- SchemaError.prototype = new Error;
+ SchemaError.prototype = new Error();
/**
* Classes that are checkable are annotated with this
* checkable info symbol, which contains the information necessary
* to check if they're valid.
*/
- let checkableInfoSym = Symbol("checkableInfo");
+ const checkableInfoSym = Symbol("checkableInfo");
/**
* Get the current property list for a checkable type.
@@ -138,7 +138,7 @@ export namespace Checkable {
throw new SchemaError(`array expected for ${path}, got ${typeof target} instead`);
}
for (let i = 0; i < target.length; i++) {
- let v = target[i];
+ const v = target[i];
prop.elementChecker(v, prop.elementProp, path.concat([i]));
}
return target;
@@ -148,9 +148,9 @@ export namespace Checkable {
if (typeof target !== "object") {
throw new SchemaError(`expected object for ${path}, got ${typeof target} instead`);
}
- for (let key in target) {
+ for (const key in target) {
prop.keyProp.checker(key, prop.keyProp, path.concat([key]));
- let value = target[key];
+ const value = target[key];
prop.valueProp.checker(value, prop.valueProp, path.concat([key]));
}
}
@@ -166,35 +166,35 @@ export namespace Checkable {
function checkValue(target: any, prop: Prop, path: Path): any {
- let type = prop.type;
+ const type = prop.type;
if (!type) {
throw Error(`assertion failed (prop is ${JSON.stringify(prop)})`);
}
- let v = target;
+ const v = target;
if (!v || typeof v !== "object") {
throw new SchemaError(
`expected object for ${path.join(".")}, got ${typeof v} instead`);
}
- let props = type.prototype[checkableInfoSym].props;
- let remainingPropNames = new Set(Object.getOwnPropertyNames(v));
- let obj = new type();
- for (let prop of props) {
- if (!remainingPropNames.has(prop.propertyKey)) {
- if (prop.optional) {
+ const props = type.prototype[checkableInfoSym].props;
+ const remainingPropNames = new Set(Object.getOwnPropertyNames(v));
+ const obj = new type();
+ for (const innerProp of props) {
+ if (!remainingPropNames.has(innerProp.propertyKey)) {
+ if (innerProp.optional) {
continue;
}
- throw new SchemaError(`Property ${prop.propertyKey} missing on ${path}`);
+ throw new SchemaError(`Property ${innerProp.propertyKey} missing on ${path}`);
}
- if (!remainingPropNames.delete(prop.propertyKey)) {
+ if (!remainingPropNames.delete(innerProp.propertyKey)) {
throw new SchemaError("assertion failed");
}
- let propVal = v[prop.propertyKey];
- obj[prop.propertyKey] = prop.checker(propVal,
- prop,
- path.concat([prop.propertyKey]));
+ const propVal = v[innerProp.propertyKey];
+ obj[innerProp.propertyKey] = innerProp.checker(propVal,
+ innerProp,
+ path.concat([innerProp.propertyKey]));
}
- if (!prop.extraAllowed && remainingPropNames.size != 0) {
+ if (!prop.extraAllowed && remainingPropNames.size !== 0) {
throw new SchemaError("superfluous properties " + JSON.stringify(Array.from(
remainingPropNames.values())));
}
@@ -210,14 +210,14 @@ export namespace Checkable {
export function Class(opts: {extra?: boolean, validate?: boolean} = {}) {
return (target: any) => {
target.checked = (v: any) => {
- let cv = checkValue(v, {
+ const cv = checkValue(v, {
+ checker: checkValue,
+ extraAllowed: !!opts.extra,
propertyKey: "(root)",
type: target,
- extraAllowed: !!opts.extra,
- checker: checkValue
}, ["(root)"]);
if (opts.validate) {
- let instance = new target();
+ const instance = new target();
if (typeof instance.validate !== "function") {
throw Error("invalid Checkable annotion: validate method required");
}
@@ -227,7 +227,7 @@ export namespace Checkable {
return cv;
};
return target;
- }
+ };
}
@@ -238,12 +238,12 @@ export namespace Checkable {
if (!type) {
throw Error("Type does not exist yet (wrong order of definitions?)");
}
- function deco(target: Object, propertyKey: string | symbol): void {
- let chk = getCheckableInfo(target);
+ function deco(target: object, propertyKey: string | symbol): void {
+ const chk = getCheckableInfo(target);
chk.props.push({
- propertyKey: propertyKey,
checker: checkValue,
- type: type
+ propertyKey,
+ type,
});
}
@@ -256,20 +256,20 @@ export namespace Checkable {
* an annotation for a list of strings.
*/
export function List(type: any) {
- let stub = {};
+ const stub = {};
type(stub, "(list-element)");
- let elementProp = getCheckableInfo(stub).props[0];
- let elementChecker = elementProp.checker;
+ const elementProp = getCheckableInfo(stub).props[0];
+ const elementChecker = elementProp.checker;
if (!elementChecker) {
throw Error("assertion failed");
}
- function deco(target: Object, propertyKey: string | symbol): void {
- let chk = getCheckableInfo(target);
+ function deco(target: object, propertyKey: string | symbol): void {
+ const chk = getCheckableInfo(target);
chk.props.push({
+ checker: checkList,
elementChecker,
elementProp,
- propertyKey: propertyKey,
- checker: checkList,
+ propertyKey,
});
}
@@ -282,25 +282,25 @@ export namespace Checkable {
* one for the key type and one for the value type.
*/
export function Map(keyType: any, valueType: any) {
- let keyStub = {};
+ const keyStub = {};
keyType(keyStub, "(map-key)");
- let keyProp = getCheckableInfo(keyStub).props[0];
+ const keyProp = getCheckableInfo(keyStub).props[0];
if (!keyProp) {
throw Error("assertion failed");
}
- let valueStub = {};
+ const valueStub = {};
valueType(valueStub, "(map-value)");
- let valueProp = getCheckableInfo(valueStub).props[0];
+ const valueProp = getCheckableInfo(valueStub).props[0];
if (!valueProp) {
throw Error("assertion failed");
}
- function deco(target: Object, propertyKey: string | symbol): void {
- let chk = getCheckableInfo(target);
+ function deco(target: object, propertyKey: string | symbol): void {
+ const chk = getCheckableInfo(target);
chk.props.push({
+ checker: checkMap,
keyProp,
+ propertyKey,
valueProp,
- propertyKey: propertyKey,
- checker: checkMap,
});
}
@@ -312,21 +312,21 @@ export namespace Checkable {
* Makes another annotation optional, for example `@Checkable.Optional(Checkable.Number)`.
*/
export function Optional(type: any) {
- let stub = {};
+ const stub = {};
type(stub, "(optional-element)");
- let elementProp = getCheckableInfo(stub).props[0];
- let elementChecker = elementProp.checker;
+ const elementProp = getCheckableInfo(stub).props[0];
+ const elementChecker = elementProp.checker;
if (!elementChecker) {
throw Error("assertion failed");
}
- function deco(target: Object, propertyKey: string | symbol): void {
- let chk = getCheckableInfo(target);
+ function deco(target: object, propertyKey: string | symbol): void {
+ const chk = getCheckableInfo(target);
chk.props.push({
+ checker: checkOptional,
elementChecker,
elementProp,
- propertyKey: propertyKey,
- checker: checkOptional,
optional: true,
+ propertyKey,
});
}
@@ -337,20 +337,20 @@ export namespace Checkable {
/**
* Target property must be a number.
*/
- export function Number(target: Object, propertyKey: string | symbol): void {
- let chk = getCheckableInfo(target);
- chk.props.push({ propertyKey: propertyKey, checker: checkNumber });
+ export function Number(target: object, propertyKey: string | symbol): void {
+ const chk = getCheckableInfo(target);
+ chk.props.push({checker: checkNumber, propertyKey});
}
/**
* Target property must be an arbitary object.
*/
- export function AnyObject(target: Object, propertyKey: string | symbol): void {
- let chk = getCheckableInfo(target);
+ export function AnyObject(target: object, propertyKey: string | symbol): void {
+ const chk = getCheckableInfo(target);
chk.props.push({
- propertyKey: propertyKey,
- checker: checkAnyObject
+ checker: checkAnyObject,
+ propertyKey,
});
}
@@ -361,12 +361,12 @@ export namespace Checkable {
* Not useful by itself, but in combination with higher-order annotations
* such as List or Map.
*/
- export function Any(target: Object, propertyKey: string | symbol): void {
- let chk = getCheckableInfo(target);
+ export function Any(target: object, propertyKey: string | symbol): void {
+ const chk = getCheckableInfo(target);
chk.props.push({
- propertyKey: propertyKey,
checker: checkAny,
- optional: true
+ optional: true,
+ propertyKey,
});
}
@@ -374,16 +374,16 @@ export namespace Checkable {
/**
* Target property must be a string.
*/
- export function String(target: Object, propertyKey: string | symbol): void {
- let chk = getCheckableInfo(target);
- chk.props.push({ propertyKey: propertyKey, checker: checkString });
+ export function String(target: object, propertyKey: string | symbol): void {
+ const chk = getCheckableInfo(target);
+ chk.props.push({ checker: checkString, propertyKey });
}
/**
* Target property must be a boolean value.
*/
- export function Boolean(target: Object, propertyKey: string | symbol): void {
- let chk = getCheckableInfo(target);
- chk.props.push({ propertyKey: propertyKey, checker: checkBoolean });
+ export function Boolean(target: object, propertyKey: string | symbol): void {
+ const chk = getCheckableInfo(target);
+ chk.props.push({ checker: checkBoolean, propertyKey });
}
}
diff --git a/src/chromeBadge.ts b/src/chromeBadge.ts
index 369a95227..13716a64a 100644
--- a/src/chromeBadge.ts
+++ b/src/chromeBadge.ts
@@ -15,7 +15,7 @@
*/
import {
- Badge
+ Badge,
} from "./wallet";
@@ -85,7 +85,7 @@ export class ChromeBadge implements Badge {
constructor(window?: Window) {
// Allow injecting another window for testing
- let bg = window || chrome.extension.getBackgroundPage();
+ const bg = window || chrome.extension.getBackgroundPage();
if (!bg) {
throw Error("no window available");
}
@@ -130,13 +130,11 @@ export class ChromeBadge implements Badge {
this.ctx.lineWidth = 2.5;
if (this.animationRunning) {
/* Draw circle around the "T" with an opening of this.gapWidth */
- this.ctx.arc(0, 0,
- this.canvas.width / 2 - 2, /* radius */
- this.rotationAngle / ChromeBadge.rotationAngleMax * Math.PI * 2,
- ((this.rotationAngle + ChromeBadge.rotationAngleMax - this.gapWidth) / ChromeBadge.rotationAngleMax) * Math.PI * 2,
- false);
- }
- else {
+ const aMax = ChromeBadge.rotationAngleMax;
+ const startAngle = this.rotationAngle / aMax * Math.PI * 2;
+ const stopAngle = ((this.rotationAngle + aMax - this.gapWidth) / aMax) * Math.PI * 2;
+ this.ctx.arc(0, 0, this.canvas.width / 2 - 2, /* radius */ startAngle, stopAngle, false);
+ } else {
/* Draw full circle */
this.ctx.arc(0, 0,
this.canvas.width / 2 - 2, /* radius */
@@ -149,12 +147,13 @@ export class ChromeBadge implements Badge {
this.ctx.translate(-this.canvas.width / 2, -this.canvas.height / 2);
// Allow running outside the extension for testing
+ // tslint:disable-next-line:no-string-literal
if (window["chrome"] && window.chrome["browserAction"]) {
try {
- let imageData = this.ctx.getImageData(0,
- 0,
- this.canvas.width,
- this.canvas.height);
+ const imageData = this.ctx.getImageData(0,
+ 0,
+ this.canvas.width,
+ this.canvas.height);
chrome.browserAction.setIcon({imageData});
} catch (e) {
// Might fail if browser has over-eager canvas fingerprinting countermeasures.
@@ -168,20 +167,20 @@ export class ChromeBadge implements Badge {
return;
}
this.animationRunning = true;
- let start: number|undefined = undefined;
- let step = (timestamp: number) => {
+ let start: number|undefined;
+ const step = (timestamp: number) => {
if (!this.animationRunning) {
return;
}
if (!start) {
start = timestamp;
}
- let delta = (timestamp - start);
- if (!this.isBusy && 0 == this.gapWidth) {
+ if (!this.isBusy && 0 === this.gapWidth) {
// stop if we're close enough to origin
this.rotationAngle = 0;
} else {
- this.rotationAngle = (this.rotationAngle + (timestamp - start) * ChromeBadge.rotationSpeed) % ChromeBadge.rotationAngleMax;
+ this.rotationAngle = (this.rotationAngle + (timestamp - start) *
+ ChromeBadge.rotationSpeed) % ChromeBadge.rotationAngleMax;
}
if (this.isBusy) {
if (this.gapWidth < ChromeBadge.openMax) {
@@ -190,15 +189,13 @@ export class ChromeBadge implements Badge {
if (this.gapWidth > ChromeBadge.openMax) {
this.gapWidth = ChromeBadge.openMax;
}
- }
- else {
+ } else {
if (this.gapWidth > 0) {
this.gapWidth--;
this.gapWidth *= ChromeBadge.closeSpeed;
}
}
-
if (this.isBusy || this.gapWidth > 0) {
start = timestamp;
rAF(step);
diff --git a/src/components.ts b/src/components.ts
index bef3cff42..9d1127e99 100644
--- a/src/components.ts
+++ b/src/components.ts
@@ -17,7 +17,7 @@
/**
* General helper React components.
- *
+ *
* @author Florian Dold
*/
diff --git a/src/content_scripts/notify.ts b/src/content_scripts/notify.ts
index 64414e0b9..733367a59 100644
--- a/src/content_scripts/notify.ts
+++ b/src/content_scripts/notify.ts
@@ -14,6 +14,7 @@
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
+// tslint:disable:no-unused-expression
/**
* Module that is injected into (all!) pages to allow them
@@ -55,9 +56,9 @@ interface Handler {
const handlers: Handler[] = [];
function hashContract(contract: string): Promise<string> {
- let walletHashContractMsg = {
+ const walletHashContractMsg = {
+ detail: {contract},
type: "hash-contract",
- detail: {contract}
};
return new Promise<string>((resolve, reject) => {
chrome.runtime.sendMessage(walletHashContractMsg, (resp: any) => {
@@ -72,8 +73,8 @@ function hashContract(contract: string): Promise<string> {
function queryPayment(url: string): Promise<any> {
const walletMsg = {
- type: "query-payment",
detail: { url },
+ type: "query-payment",
};
return new Promise((resolve, reject) => {
chrome.runtime.sendMessage(walletMsg, (resp: any) => {
@@ -84,10 +85,10 @@ function queryPayment(url: string): Promise<any> {
function putHistory(historyEntry: any): Promise<void> {
const walletMsg = {
- type: "put-history-entry",
detail: {
historyEntry,
},
+ type: "put-history-entry",
};
return new Promise<void>((resolve, reject) => {
chrome.runtime.sendMessage(walletMsg, (resp: any) => {
@@ -98,14 +99,14 @@ function putHistory(historyEntry: any): Promise<void> {
function saveOffer(offer: any): Promise<number> {
const walletMsg = {
- type: "save-offer",
detail: {
offer: {
+ H_contract: offer.hash,
contract: offer.data,
merchant_sig: offer.sig,
- H_contract: offer.hash,
- offer_time: new Date().getTime() / 1000
+ offer_time: new Date().getTime() / 1000,
},
+ type: "save-offer",
},
};
return new Promise<number>((resolve, reject) => {
@@ -120,15 +121,13 @@ function saveOffer(offer: any): Promise<number> {
}
-
-
let sheet: CSSStyleSheet|null;
function initStyle() {
logVerbose && console.log("taking over styles");
const name = "taler-presence-stylesheet";
const content = "/* Taler stylesheet controlled by JS */";
- let style = document.getElementById(name) as HTMLStyleElement|null;
+ let style = document.getElementById(name) as HTMLStyleElement|null;
if (!style) {
style = document.createElement("style");
// Needed by WebKit
@@ -170,7 +169,6 @@ function setStyles(installed: boolean) {
}
-
function handlePaymentResponse(walletResp: any) {
/**
* Handle a failed payment.
@@ -185,16 +183,16 @@ function handlePaymentResponse(walletResp: any) {
console.log("pay-failed", {status: r.status, response: r.responseText});
}
function onTimeout() {
- timeoutHandle = null
+ timeoutHandle = null;
err();
}
talerPaymentFailed(walletResp.H_contract).then(() => {
- if (timeoutHandle != null) {
+ if (timeoutHandle !== null) {
clearTimeout(timeoutHandle);
timeoutHandle = null;
}
err();
- })
+ });
timeoutHandle = window.setTimeout(onTimeout, 200);
}
@@ -210,7 +208,7 @@ function handlePaymentResponse(walletResp: any) {
r.open("post", walletResp.contract.pay_url);
r.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
r.send(JSON.stringify(walletResp.payReq));
- r.onload = function() {
+ r.onload = () => {
if (!r) {
return;
}
@@ -219,7 +217,7 @@ function handlePaymentResponse(walletResp: any) {
const merchantResp = JSON.parse(r.responseText);
logVerbose && console.log("got success from pay_url");
talerPaymentSucceeded({H_contract: walletResp.H_contract, merchantSig: merchantResp.sig}).then(() => {
- let nextUrl = walletResp.contract.fulfillment_url;
+ const nextUrl = walletResp.contract.fulfillment_url;
logVerbose && console.log("taler-payment-succeeded done, going to", nextUrl);
window.location.href = nextUrl;
window.location.reload(true);
@@ -230,7 +228,7 @@ function handlePaymentResponse(walletResp: any) {
break;
}
r = null;
- if (timeoutHandle != null) {
+ if (timeoutHandle !== null) {
clearTimeout(timeoutHandle!);
timeoutHandle = null;
}
@@ -262,7 +260,7 @@ function init() {
initStyle();
setStyles(true);
};
- if (document.readyState == "complete") {
+ if (document.readyState === "complete") {
onload();
} else {
document.addEventListener("DOMContentLoaded", onload);
@@ -270,19 +268,19 @@ function init() {
}
registerHandlers();
// Hack to know when the extension is unloaded
- let port = chrome.runtime.connect();
+ const port = chrome.runtime.connect();
port.onDisconnect.addListener(() => {
logVerbose && console.log("chrome runtime disconnected, removing handlers");
if (document.documentElement.getAttribute("data-taler-nojs")) {
setStyles(false);
}
- for (let handler of handlers) {
+ for (const handler of handlers) {
document.removeEventListener(handler.type, handler.listener);
}
});
- if (resp && resp.type == "pay") {
+ if (resp && resp.type === "pay") {
logVerbose && console.log("doing taler.pay with", resp.payDetail);
talerPay(resp.payDetail).then(handlePaymentResponse);
document.documentElement.style.visibility = "hidden";
@@ -290,9 +288,7 @@ function init() {
});
}
-interface HandlerFn {
- (detail: any, sendResponse: (msg: any) => void): void;
-}
+type HandlerFn = (detail: any, sendResponse: (msg: any) => void) => void;
function generateNonce(): Promise<string> {
const walletMsg = {
@@ -306,35 +302,47 @@ function generateNonce(): Promise<string> {
}
function downloadContract(url: string, nonce: string): Promise<any> {
- let parsed_url = new URI(url);
+ const parsed_url = new URI(url);
url = parsed_url.setQuery({nonce}).href();
// FIXME: include and check nonce!
return new Promise((resolve, reject) => {
const contract_request = new XMLHttpRequest();
- console.log("downloading contract from '" + url + "'")
+ console.log("downloading contract from '" + url + "'");
contract_request.open("GET", url, true);
- contract_request.onload = function (e) {
- if (contract_request.readyState == 4) {
- if (contract_request.status == 200) {
+ contract_request.onload = (e) => {
+ if (contract_request.readyState === 4) {
+ if (contract_request.status === 200) {
console.log("response text:",
contract_request.responseText);
- var contract_wrapper = JSON.parse(contract_request.responseText);
+ const contract_wrapper = JSON.parse(contract_request.responseText);
if (!contract_wrapper) {
console.error("response text was invalid json");
- let detail = {hint: "invalid json", status: contract_request.status, body: contract_request.responseText};
+ const detail = {
+ body: contract_request.responseText,
+ hint: "invalid json",
+ status: contract_request.status,
+ };
reject(detail);
return;
}
resolve(contract_wrapper);
} else {
- let detail = {hint: "contract download failed", status: contract_request.status, body: contract_request.responseText};
+ const detail = {
+ body: contract_request.responseText,
+ hint: "contract download failed",
+ status: contract_request.status,
+ };
reject(detail);
return;
}
}
};
- contract_request.onerror = function (e) {
- let detail = {hint: "contract download failed", status: contract_request.status, body: contract_request.responseText};
+ contract_request.onerror = (e) => {
+ const detail = {
+ body: contract_request.responseText,
+ hint: "contract download failed",
+ status: contract_request.status,
+ };
reject(detail);
return;
};
@@ -353,9 +361,9 @@ async function processProposal(proposal: any) {
return;
}
- let contractHash = await hashContract(proposal.data);
+ const contractHash = await hashContract(proposal.data);
- if (contractHash != proposal.hash) {
+ if (contractHash !== proposal.hash) {
console.error("merchant-supplied contract hash is wrong");
return;
}
@@ -367,17 +375,17 @@ async function processProposal(proposal: any) {
// bad contract / name not included
}
- let historyEntry = {
- timestamp: (new Date).getTime(),
- subjectId: `contract-${contractHash}`,
- type: "offer-contract",
+ const historyEntry = {
detail: {
contractHash,
merchantName,
- }
+ },
+ subjectId: `contract-${contractHash}`,
+ timestamp: (new Date()).getTime(),
+ type: "offer-contract",
};
await putHistory(historyEntry);
- let offerId = await saveOffer(proposal);
+ const offerId = await saveOffer(proposal);
const uri = new URI(chrome.extension.getURL(
"/src/pages/confirm-contract.html"));
@@ -391,17 +399,17 @@ async function processProposal(proposal: any) {
function talerPay(msg: any): Promise<any> {
return new Promise(async(resolve, reject) => {
// current URL without fragment
- let url = new URI(document.location.href).fragment("").href();
- let res = await queryPayment(url);
+ const url = new URI(document.location.href).fragment("").href();
+ const res = await queryPayment(url);
logVerbose && console.log("taler-pay: got response", res);
if (res && res.payReq) {
resolve(res);
return;
}
if (msg.contract_url) {
- let nonce = await generateNonce();
- let proposal = await downloadContract(msg.contract_url, nonce);
- if (proposal.data.nonce != nonce) {
+ const nonce = await generateNonce();
+ const proposal = await downloadContract(msg.contract_url, nonce);
+ if (proposal.data.nonce !== nonce) {
console.error("stale contract");
return;
}
@@ -421,10 +429,10 @@ function talerPay(msg: any): Promise<any> {
function talerPaymentFailed(H_contract: string) {
return new Promise(async(resolve, reject) => {
const walletMsg = {
- type: "payment-failed",
detail: {
- contractHash: H_contract
+ contractHash: H_contract,
},
+ type: "payment-failed",
};
chrome.runtime.sendMessage(walletMsg, (resp) => {
resolve();
@@ -444,11 +452,11 @@ function talerPaymentSucceeded(msg: any) {
}
logVerbose && console.log("got taler-payment-succeeded");
const walletMsg = {
- type: "payment-succeeded",
detail: {
- merchantSig: msg.merchantSig,
contractHash: msg.H_contract,
+ merchantSig: msg.merchantSig,
},
+ type: "payment-succeeded",
};
chrome.runtime.sendMessage(walletMsg, (resp) => {
resolve();
@@ -463,21 +471,21 @@ function registerHandlers() {
* handles adding sequence numbers to responses.
*/
function addHandler(type: string, handler: HandlerFn) {
- let handlerWrap = (e: CustomEvent) => {
- if (e.type != type) {
+ const handlerWrap = (e: CustomEvent) => {
+ if (e.type !== type) {
throw Error(`invariant violated`);
}
- let callId: number|undefined = undefined;
- if (e.detail && e.detail.callId != undefined) {
+ let callId: number|undefined;
+ if (e.detail && e.detail.callId !== undefined) {
callId = e.detail.callId;
}
- let responder = (msg?: any) => {
- let fullMsg = Object.assign({}, msg, {callId});
+ const responder = (msg?: any) => {
+ const fullMsg = Object.assign({}, msg, {callId});
let opts = { detail: fullMsg };
- if ("function" == typeof cloneInto) {
+ if ("function" === typeof cloneInto) {
opts = cloneInto(opts, document.defaultView);
}
- let evt = new CustomEvent(type + "-result", opts);
+ const evt = new CustomEvent(type + "-result", opts);
document.dispatchEvent(evt);
};
handler(e.detail, responder);
@@ -489,7 +497,7 @@ function registerHandlers() {
addHandler("taler-query-id", (msg: any, sendResponse: any) => {
// FIXME: maybe include this info in taoer-probe?
- sendResponse({id: chrome.runtime.id})
+ sendResponse({id: chrome.runtime.id});
});
addHandler("taler-probe", (msg: any, sendResponse: any) => {
@@ -497,34 +505,33 @@ function registerHandlers() {
});
addHandler("taler-create-reserve", (msg: any) => {
- let params = {
+ const params = {
amount: JSON.stringify(msg.amount),
- callback_url: new URI(msg.callback_url)
- .absoluteTo(document.location.href),
bank_url: document.location.href,
- wt_types: JSON.stringify(msg.wt_types),
+ callback_url: new URI(msg.callback_url) .absoluteTo(document.location.href),
suggested_exchange_url: msg.suggested_exchange_url,
+ wt_types: JSON.stringify(msg.wt_types),
};
- let uri = new URI(chrome.extension.getURL("/src/pages/confirm-create-reserve.html"));
- let redirectUrl = uri.query(params).href();
+ const uri = new URI(chrome.extension.getURL("/src/pages/confirm-create-reserve.html"));
+ const redirectUrl = uri.query(params).href();
window.location.href = redirectUrl;
});
addHandler("taler-add-auditor", (msg: any) => {
- let params = {
+ const params = {
req: JSON.stringify(msg),
};
- let uri = new URI(chrome.extension.getURL("/src/pages/add-auditor.html"));
- let redirectUrl = uri.query(params).href();
+ const uri = new URI(chrome.extension.getURL("/src/pages/add-auditor.html"));
+ const redirectUrl = uri.query(params).href();
window.location.href = redirectUrl;
});
addHandler("taler-confirm-reserve", (msg: any, sendResponse: any) => {
- let walletMsg = {
- type: "confirm-reserve",
+ const walletMsg = {
detail: {
- reservePub: msg.reserve_pub
- }
+ reservePub: msg.reserve_pub,
+ },
+ type: "confirm-reserve",
};
chrome.runtime.sendMessage(walletMsg, (resp) => {
sendResponse();
@@ -544,7 +551,7 @@ function registerHandlers() {
});
addHandler("taler-pay", async(msg: any, sendResponse: any) => {
- let resp = await talerPay(msg);
+ const resp = await talerPay(msg);
sendResponse(resp);
});
diff --git a/src/crypto/cryptoApi-test.ts b/src/crypto/cryptoApi-test.ts
index cc5d1156e..60bd44c90 100644
--- a/src/crypto/cryptoApi-test.ts
+++ b/src/crypto/cryptoApi-test.ts
@@ -1,80 +1,104 @@
-import {CryptoApi} from "./cryptoApi";
-import {ReserveRecord, DenominationRecord, DenominationStatus} from "../types";
+/*
+ This file is part of TALER
+ (C) 2017 Inria and 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, see <http://www.gnu.org/licenses/>
+ */
+
+// tslint:disable:max-line-length
+
import {test} from "ava";
-let masterPub1: string = "CQQZ9DY3MZ1ARMN5K1VKDETS04Y2QCKMMCFHZSWJWWVN82BTTH00";
+import {
+ DenominationRecord,
+ DenominationStatus,
+ ReserveRecord,
+} from "../types";
-let denomValid1: DenominationRecord = {
- masterSig: "CJFJCQ48Q45PSGJ5KY94N6M2TPARESM2E15BSPBD95YVVPEARAEQ6V6G4Z2XBMS0QM0F3Y9EYVP276FCS90EQ1578ZC8JHFBZ3NGP3G",
- stampStart: "/Date(1473148381)/",
- stampExpireWithdraw: "/Date(2482300381)/",
- stampExpireDeposit: "/Date(1851580381)/",
+import {CryptoApi} from "./cryptoApi";
+
+const masterPub1: string = "CQQZ9DY3MZ1ARMN5K1VKDETS04Y2QCKMMCFHZSWJWWVN82BTTH00";
+
+const denomValid1: DenominationRecord = {
denomPub: "51R7ARKCD5HJTTV5F4G0M818E9SP280A40G2GVH04CR30GHS84R3JHHP6GSM2D9Q6514CGT568R32C9J6CWM4DSH64TM4DSM851K0CA48CVKAC1P6H144C2160T46DHK8CVM4HJ274S38C1M6S338D9N6GWM8DT684T3JCT36S13EC9G88R3EGHQ8S0KJGSQ60SKGD216N33AGJ2651K2E9S60TMCD1N75244HHQ6X33EDJ570R3GGJ2651MACA38D130DA560VK4HHJ68WK2CA26GW3ECSH6D13EC9S88VK2GT66WVK8D9G750K0D9R8RRK4DHQ71332GHK8D23GE26710M2H9K6WVK8HJ38MVKEGA66N23AC9H88VKACT58MV3CCSJ6H1K4DT38GRK0C9M8N33CE1R60V4AHA38H1KECSH6S33JH9N8GRKGH1K68S36GH354520818CMG26C1H60R30C935452081918G2J2G0",
- stampExpireLegal: "/Date(1567756381)/",
- value: {
- "currency": "PUDOS",
- "value": 0,
- "fraction": 100000
- },
- feeWithdraw: {
- "currency": "PUDOS",
- "value": 0,
- "fraction": 10000
- },
+ denomPubHash: "dummy",
+ exchangeBaseUrl: "https://exchange.example.com/",
feeDeposit: {
- "currency": "PUDOS",
- "value": 0,
- "fraction": 10000
+ currency: "PUDOS",
+ fraction: 10000,
+ value: 0,
},
feeRefresh: {
- "currency": "PUDOS",
- "value": 0,
- "fraction": 10000
+ currency: "PUDOS",
+ fraction: 10000,
+ value: 0,
},
feeRefund: {
- "currency": "PUDOS",
- "value": 0,
- "fraction": 10000
+ currency: "PUDOS",
+ fraction: 10000,
+ value: 0,
+ },
+ feeWithdraw: {
+ currency: "PUDOS",
+ fraction: 10000,
+ value: 0,
},
- denomPubHash: "dummy",
- status: DenominationStatus.Unverified,
isOffered: true,
- exchangeBaseUrl: "https://exchange.example.com/",
+ masterSig: "CJFJCQ48Q45PSGJ5KY94N6M2TPARESM2E15BSPBD95YVVPEARAEQ6V6G4Z2XBMS0QM0F3Y9EYVP276FCS90EQ1578ZC8JHFBZ3NGP3G",
+ stampExpireDeposit: "/Date(1851580381)/",
+ stampExpireLegal: "/Date(1567756381)/",
+ stampExpireWithdraw: "/Date(2482300381)/",
+ stampStart: "/Date(1473148381)/",
+ status: DenominationStatus.Unverified,
+ value: {
+ currency: "PUDOS",
+ fraction: 100000,
+ value: 0,
+ },
};
-let denomInvalid1 = JSON.parse(JSON.stringify(denomValid1));
+const denomInvalid1 = JSON.parse(JSON.stringify(denomValid1));
denomInvalid1.value.value += 1;
-test("string hashing", async t => {
- let crypto = new CryptoApi();
- let s = await crypto.hashString("hello taler");
- let sh = "8RDMADB3YNF3QZBS3V467YZVJAMC2QAQX0TZGVZ6Q5PFRRAJFT70HHN0QF661QR9QWKYMMC7YEMPD679D2RADXCYK8Y669A2A5MKQFR";
- t.true(s == sh);
+test("string hashing", async (t) => {
+ const crypto = new CryptoApi();
+ const s = await crypto.hashString("hello taler");
+ const sh = "8RDMADB3YNF3QZBS3V467YZVJAMC2QAQX0TZGVZ6Q5PFRRAJFT70HHN0QF661QR9QWKYMMC7YEMPD679D2RADXCYK8Y669A2A5MKQFR";
+ t.true(s === sh);
t.pass();
});
-test("precoin creation", async t => {
- let crypto = new CryptoApi();
- let {priv, pub} = await crypto.createEddsaKeypair();
- let r: ReserveRecord = {
- reserve_pub: pub,
- reserve_priv: priv,
- hasPayback: false,
- exchange_base_url: "https://example.com/exchange",
+test("precoin creation", async (t) => {
+ const crypto = new CryptoApi();
+ const {priv, pub} = await crypto.createEddsaKeypair();
+ const r: ReserveRecord = {
+ confirmed: false,
created: 0,
- requested_amount: {currency: "PUDOS", value: 0, fraction: 0},
- precoin_amount: {currency: "PUDOS", value: 0, fraction: 0},
current_amount: null,
- confirmed: false,
+ exchange_base_url: "https://example.com/exchange",
+ hasPayback: false,
last_query: null,
+ precoin_amount: {currency: "PUDOS", value: 0, fraction: 0},
+ requested_amount: {currency: "PUDOS", value: 0, fraction: 0},
+ reserve_priv: priv,
+ reserve_pub: pub,
};
- let precoin = await crypto.createPreCoin(denomValid1, r);
+ const precoin = await crypto.createPreCoin(denomValid1, r);
t.pass();
});
-test("denom validation", async t => {
- let crypto = new CryptoApi();
+test("denom validation", async (t) => {
+ const crypto = new CryptoApi();
let v: boolean;
v = await crypto.isValidDenom(denomValid1, masterPub1);
t.true(v);
diff --git a/src/crypto/cryptoApi.ts b/src/crypto/cryptoApi.ts
index b291cd17d..57f035a83 100644
--- a/src/crypto/cryptoApi.ts
+++ b/src/crypto/cryptoApi.ts
@@ -24,20 +24,22 @@
* Imports.
*/
import {
- PreCoinRecord,
- CoinRecord,
- ReserveRecord,
AmountJson,
+ CoinRecord,
DenominationRecord,
+ PayCoinInfo,
PaybackRequest,
+ PreCoinRecord,
RefreshSessionRecord,
+ ReserveRecord,
WireFee,
- PayCoinInfo,
} from "../types";
+
import {
- OfferRecord,
CoinWithDenom,
+ OfferRecord,
} from "../wallet";
+
import * as timer from "../timer";
import { startWorker } from "./startWorker";
@@ -76,8 +78,6 @@ interface WorkItem {
}
-
-
/**
* Number of different priorities. Each priority p
* must be 0 <= p < NUM_PRIO.
@@ -97,34 +97,35 @@ export class CryptoApi {
* Start a worker (if not started) and set as busy.
*/
wake<T>(ws: WorkerState, work: WorkItem): void {
- if (ws.currentWorkItem != null) {
+ if (ws.currentWorkItem !== null) {
throw Error("assertion failed");
}
ws.currentWorkItem = work;
this.numBusy++;
if (!ws.w) {
- let w = startWorker();
+ const w = startWorker();
w.onmessage = (m: MessageEvent) => this.handleWorkerMessage(ws, m);
w.onerror = (e: ErrorEvent) => this.handleWorkerError(ws, e);
ws.w = w;
}
- let msg: any = {
- operation: work.operation, args: work.args,
- id: work.rpcId
+ const msg: any = {
+ args: work.args,
+ id: work.rpcId,
+ operation: work.operation,
};
this.resetWorkerTimeout(ws);
ws.w!.postMessage(msg);
}
resetWorkerTimeout(ws: WorkerState) {
- if (ws.terminationTimerHandle != null) {
+ if (ws.terminationTimerHandle !== null) {
ws.terminationTimerHandle.clear();
ws.terminationTimerHandle = null;
}
- let destroy = () => {
+ const destroy = () => {
// terminate worker if it's idle
- if (ws.w && ws.currentWorkItem == null) {
+ if (ws.w && ws.currentWorkItem === null) {
ws.w!.terminate();
ws.w = null;
}
@@ -146,7 +147,7 @@ export class CryptoApi {
} catch (e) {
console.error(e);
}
- if (ws.currentWorkItem != null) {
+ if (ws.currentWorkItem !== null) {
ws.currentWorkItem.reject(e);
ws.currentWorkItem = null;
this.numBusy--;
@@ -157,9 +158,9 @@ export class CryptoApi {
findWork(ws: WorkerState) {
// try to find more work for this worker
for (let i = 0; i < NUM_PRIO; i++) {
- let q = this.workQueues[NUM_PRIO - i - 1];
- if (q.length != 0) {
- let work: WorkItem = q.shift()!;
+ const q = this.workQueues[NUM_PRIO - i - 1];
+ if (q.length !== 0) {
+ const work: WorkItem = q.shift()!;
this.wake(ws, work);
return;
}
@@ -167,12 +168,12 @@ export class CryptoApi {
}
handleWorkerMessage(ws: WorkerState, msg: MessageEvent) {
- let id = msg.data.id;
+ const id = msg.data.id;
if (typeof id !== "number") {
console.error("rpc id must be number");
return;
}
- let currentWorkItem = ws.currentWorkItem;
+ const currentWorkItem = ws.currentWorkItem;
ws.currentWorkItem = null;
this.numBusy--;
this.findWork(ws);
@@ -180,7 +181,7 @@ export class CryptoApi {
console.error("unsolicited response from worker");
return;
}
- if (id != currentWorkItem.rpcId) {
+ if (id !== currentWorkItem.rpcId) {
console.error(`RPC with id ${id} has no registry entry`);
return;
}
@@ -191,6 +192,7 @@ export class CryptoApi {
let concurrency = 2;
try {
// only works in the browser
+ // tslint:disable-next-line:no-string-literal
concurrency = (navigator as any)["hardwareConcurrency"];
} catch (e) {
// ignore
@@ -199,9 +201,9 @@ export class CryptoApi {
for (let i = 0; i < this.workers.length; i++) {
this.workers[i] = {
- w: null,
- terminationTimerHandle: null,
currentWorkItem: null,
+ terminationTimerHandle: null,
+ w: null,
};
}
this.workQueues = [];
@@ -212,14 +214,14 @@ export class CryptoApi {
private doRpc<T>(operation: string, priority: number,
...args: any[]): Promise<T> {
- let start = timer.performanceNow();
+ const start = timer.performanceNow();
- let p = new Promise((resolve, reject) => {
- let rpcId = this.nextRpcId++;
- let workItem: WorkItem = {operation, args, resolve, reject, rpcId};
+ const p = new Promise((resolve, reject) => {
+ const rpcId = this.nextRpcId++;
+ const workItem: WorkItem = {operation, args, resolve, reject, rpcId};
- if (this.numBusy == this.workers.length) {
- let q = this.workQueues[priority];
+ if (this.numBusy === this.workers.length) {
+ const q = this.workQueues[priority];
if (!q) {
throw Error("assertion failed");
}
@@ -227,9 +229,8 @@ export class CryptoApi {
return;
}
- for (let i = 0; i < this.workers.length; i++) {
- let ws = this.workers[i];
- if (ws.currentWorkItem != null) {
+ for (const ws of this.workers) {
+ if (ws.currentWorkItem !== null) {
continue;
}
diff --git a/src/crypto/cryptoWorker.ts b/src/crypto/cryptoWorker.ts
index 36b3b924a..9541b7442 100644
--- a/src/crypto/cryptoWorker.ts
+++ b/src/crypto/cryptoWorker.ts
@@ -37,12 +37,11 @@ import {
ReserveRecord,
WireFee,
} from "../types";
-import create = chrome.alarms.create;
import {
CoinWithDenom,
OfferRecord,
} from "../wallet";
-import * as native from "./emscInterface";
+
import {
Amount,
EddsaPublicKey,
@@ -50,6 +49,7 @@ import {
HashContext,
RefreshMeltCoinAffirmationPS,
} from "./emscInterface";
+import * as native from "./emscInterface";
namespace RpcFunctions {
@@ -60,18 +60,16 @@ namespace RpcFunctions {
*/
export function createPreCoin(denom: DenominationRecord,
reserve: ReserveRecord): PreCoinRecord {
- let reservePriv = new native.EddsaPrivateKey();
+ const reservePriv = new native.EddsaPrivateKey();
reservePriv.loadCrock(reserve.reserve_priv);
- let reservePub = new native.EddsaPublicKey();
+ const reservePub = new native.EddsaPublicKey();
reservePub.loadCrock(reserve.reserve_pub);
- let denomPub = native.RsaPublicKey.fromCrock(denom.denomPub);
- let coinPriv = native.EddsaPrivateKey.create();
- let coinPub = coinPriv.getPublicKey();
- let blindingFactor = native.RsaBlindingKeySecret.create();
- let pubHash: native.HashCode = coinPub.hash();
- let ev = native.rsaBlind(pubHash,
- blindingFactor,
- denomPub);
+ const denomPub = native.RsaPublicKey.fromCrock(denom.denomPub);
+ const coinPriv = native.EddsaPrivateKey.create();
+ const coinPub = coinPriv.getPublicKey();
+ const blindingFactor = native.RsaBlindingKeySecret.create();
+ const pubHash: native.HashCode = coinPub.hash();
+ const ev = native.rsaBlind(pubHash, blindingFactor, denomPub);
if (!ev) {
throw Error("couldn't blind (malicious exchange key?)");
@@ -81,61 +79,61 @@ namespace RpcFunctions {
throw Error("Field fee_withdraw missing");
}
- let amountWithFee = new native.Amount(denom.value);
+ const amountWithFee = new native.Amount(denom.value);
amountWithFee.add(new native.Amount(denom.feeWithdraw));
- let withdrawFee = new native.Amount(denom.feeWithdraw);
+ const withdrawFee = new native.Amount(denom.feeWithdraw);
// Signature
- let withdrawRequest = new native.WithdrawRequestPS({
- reserve_pub: reservePub,
+ const withdrawRequest = new native.WithdrawRequestPS({
amount_with_fee: amountWithFee.toNbo(),
- withdraw_fee: withdrawFee.toNbo(),
+ h_coin_envelope: ev.hash(),
h_denomination_pub: denomPub.encode().hash(),
- h_coin_envelope: ev.hash()
+ reserve_pub: reservePub,
+ withdraw_fee: withdrawFee.toNbo(),
});
- var sig = native.eddsaSign(withdrawRequest.toPurpose(), reservePriv);
+ const sig = native.eddsaSign(withdrawRequest.toPurpose(), reservePriv);
- let preCoin: PreCoinRecord = {
- reservePub: reservePub.toCrock(),
+ const preCoin: PreCoinRecord = {
blindingKey: blindingFactor.toCrock(),
- coinPub: coinPub.toCrock(),
+ coinEv: ev.toCrock(),
coinPriv: coinPriv.toCrock(),
+ coinPub: coinPub.toCrock(),
+ coinValue: denom.value,
denomPub: denomPub.encode().toCrock(),
exchangeBaseUrl: reserve.exchange_base_url,
+ reservePub: reservePub.toCrock(),
withdrawSig: sig.toCrock(),
- coinEv: ev.toCrock(),
- coinValue: denom.value
};
return preCoin;
}
export function createPaybackRequest(coin: CoinRecord): PaybackRequest {
- let p = new native.PaybackRequestPS({
+ const p = new native.PaybackRequestPS({
+ coin_blind: native.RsaBlindingKeySecret.fromCrock(coin.blindingKey),
coin_pub: native.EddsaPublicKey.fromCrock(coin.coinPub),
h_denom_pub: native.RsaPublicKey.fromCrock(coin.denomPub).encode().hash(),
- coin_blind: native.RsaBlindingKeySecret.fromCrock(coin.blindingKey),
});
- let coinPriv = native.EddsaPrivateKey.fromCrock(coin.coinPriv);
- let coinSig = native.eddsaSign(p.toPurpose(), coinPriv);
- let paybackRequest: PaybackRequest = {
- denom_pub: coin.denomPub,
- denom_sig: coin.denomSig,
+ const coinPriv = native.EddsaPrivateKey.fromCrock(coin.coinPriv);
+ const coinSig = native.eddsaSign(p.toPurpose(), coinPriv);
+ const paybackRequest: PaybackRequest = {
coin_blind_key_secret: coin.blindingKey,
coin_pub: coin.coinPub,
coin_sig: coinSig.toCrock(),
+ denom_pub: coin.denomPub,
+ denom_sig: coin.denomSig,
};
return paybackRequest;
}
export function isValidPaymentSignature(sig: string, contractHash: string, merchantPub: string): boolean {
- let p = new native.PaymentSignaturePS({
+ const p = new native.PaymentSignaturePS({
contract_hash: native.HashCode.fromCrock(contractHash),
});
- let nativeSig = new native.EddsaSignature();
+ const nativeSig = new native.EddsaSignature();
nativeSig.loadCrock(sig);
- let nativePub = native.EddsaPublicKey.fromCrock(merchantPub);
+ const nativePub = native.EddsaPublicKey.fromCrock(merchantPub);
return native.eddsaVerify(native.SignaturePurpose.MERCHANT_PAYMENT_OK,
p.toPurpose(),
nativeSig,
@@ -143,17 +141,17 @@ namespace RpcFunctions {
}
export function isValidWireFee(type: string, wf: WireFee, masterPub: string): boolean {
- let p = new native.MasterWireFeePS({
+ const p = new native.MasterWireFeePS({
+ closing_fee: (new native.Amount(wf.closingFee)).toNbo(),
+ end_date: native.AbsoluteTimeNbo.fromStampSeconds(wf.endStamp),
h_wire_method: native.ByteArray.fromStringWithNull(type).hash(),
start_date: native.AbsoluteTimeNbo.fromStampSeconds(wf.startStamp),
- end_date: native.AbsoluteTimeNbo.fromStampSeconds(wf.endStamp),
wire_fee: (new native.Amount(wf.wireFee)).toNbo(),
- closing_fee: (new native.Amount(wf.closingFee)).toNbo(),
});
- let nativeSig = new native.EddsaSignature();
+ const nativeSig = new native.EddsaSignature();
nativeSig.loadCrock(wf.sig);
- let nativePub = native.EddsaPublicKey.fromCrock(masterPub);
+ const nativePub = native.EddsaPublicKey.fromCrock(masterPub);
return native.eddsaVerify(native.SignaturePurpose.MASTER_WIRE_FEES,
p.toPurpose(),
@@ -164,26 +162,24 @@ namespace RpcFunctions {
export function isValidDenom(denom: DenominationRecord,
masterPub: string): boolean {
- let p = new native.DenominationKeyValidityPS({
- master: native.EddsaPublicKey.fromCrock(masterPub),
- denom_hash: native.RsaPublicKey.fromCrock(denom.denomPub)
- .encode()
- .hash(),
+ const p = new native.DenominationKeyValidityPS({
+ denom_hash: native.RsaPublicKey.fromCrock(denom.denomPub) .encode() .hash(),
expire_legal: native.AbsoluteTimeNbo.fromTalerString(denom.stampExpireLegal),
expire_spend: native.AbsoluteTimeNbo.fromTalerString(denom.stampExpireDeposit),
expire_withdraw: native.AbsoluteTimeNbo.fromTalerString(denom.stampExpireWithdraw),
- start: native.AbsoluteTimeNbo.fromTalerString(denom.stampStart),
- value: (new native.Amount(denom.value)).toNbo(),
fee_deposit: (new native.Amount(denom.feeDeposit)).toNbo(),
fee_refresh: (new native.Amount(denom.feeRefresh)).toNbo(),
- fee_withdraw: (new native.Amount(denom.feeWithdraw)).toNbo(),
fee_refund: (new native.Amount(denom.feeRefund)).toNbo(),
+ fee_withdraw: (new native.Amount(denom.feeWithdraw)).toNbo(),
+ master: native.EddsaPublicKey.fromCrock(masterPub),
+ start: native.AbsoluteTimeNbo.fromTalerString(denom.stampStart),
+ value: (new native.Amount(denom.value)).toNbo(),
});
- let nativeSig = new native.EddsaSignature();
+ const nativeSig = new native.EddsaSignature();
nativeSig.loadCrock(denom.masterSig);
- let nativePub = native.EddsaPublicKey.fromCrock(masterPub);
+ const nativePub = native.EddsaPublicKey.fromCrock(masterPub);
return native.eddsaVerify(native.SignaturePurpose.MASTER_DENOMINATION_KEY_VALIDITY,
p.toPurpose(),
@@ -201,10 +197,10 @@ namespace RpcFunctions {
export function rsaUnblind(sig: string, bk: string, pk: string): string {
- let denomSig = native.rsaUnblind(native.RsaSignature.fromCrock(sig),
+ const denomSig = native.rsaUnblind(native.RsaSignature.fromCrock(sig),
native.RsaBlindingKeySecret.fromCrock(bk),
native.RsaPublicKey.fromCrock(pk));
- return denomSig.encode().toCrock()
+ return denomSig.encode().toCrock();
}
@@ -214,21 +210,21 @@ namespace RpcFunctions {
*/
export function signDeposit(offer: OfferRecord,
cds: CoinWithDenom[]): PayCoinInfo {
- let ret: PayCoinInfo = [];
+ const ret: PayCoinInfo = [];
- let feeList: AmountJson[] = cds.map((x) => x.denom.feeDeposit);
+ const feeList: AmountJson[] = cds.map((x) => x.denom.feeDeposit);
let fees = Amounts.add(Amounts.getZero(feeList[0].currency), ...feeList).amount;
// okay if saturates
fees = Amounts.sub(fees, offer.contract.max_fee).amount;
- let total = Amounts.add(fees, offer.contract.amount).amount;
+ const total = Amounts.add(fees, offer.contract.amount).amount;
- let amountSpent = native.Amount.getZero(cds[0].coin.currentAmount.currency);
- let amountRemaining = new native.Amount(total);
- for (let cd of cds) {
+ const amountSpent = native.Amount.getZero(cds[0].coin.currentAmount.currency);
+ const amountRemaining = new native.Amount(total);
+ for (const cd of cds) {
let coinSpend: Amount;
- if (amountRemaining.value == 0 && amountRemaining.fraction == 0) {
+ if (amountRemaining.value === 0 && amountRemaining.fraction === 0) {
break;
}
@@ -241,7 +237,7 @@ namespace RpcFunctions {
amountSpent.add(coinSpend);
amountRemaining.sub(coinSpend);
- let feeDeposit: Amount = new native.Amount(cd.denom.feeDeposit);
+ const feeDeposit: Amount = new native.Amount(cd.denom.feeDeposit);
// Give the merchant at least the deposit fee, otherwise it'll reject
// the coin.
@@ -249,32 +245,32 @@ namespace RpcFunctions {
coinSpend = feeDeposit;
}
- let newAmount = new native.Amount(cd.coin.currentAmount);
+ const newAmount = new native.Amount(cd.coin.currentAmount);
newAmount.sub(coinSpend);
cd.coin.currentAmount = newAmount.toJson();
cd.coin.status = CoinStatus.TransactionPending;
- let d = new native.DepositRequestPS({
- h_contract: native.HashCode.fromCrock(offer.H_contract),
- h_wire: native.HashCode.fromCrock(offer.contract.H_wire),
+ const d = new native.DepositRequestPS({
amount_with_fee: coinSpend.toNbo(),
coin_pub: native.EddsaPublicKey.fromCrock(cd.coin.coinPub),
deposit_fee: new native.Amount(cd.denom.feeDeposit).toNbo(),
+ h_contract: native.HashCode.fromCrock(offer.H_contract),
+ h_wire: native.HashCode.fromCrock(offer.contract.H_wire),
merchant: native.EddsaPublicKey.fromCrock(offer.contract.merchant_pub),
refund_deadline: native.AbsoluteTimeNbo.fromTalerString(offer.contract.refund_deadline),
timestamp: native.AbsoluteTimeNbo.fromTalerString(offer.contract.timestamp),
});
- let coinSig = native.eddsaSign(d.toPurpose(),
+ const coinSig = native.eddsaSign(d.toPurpose(),
native.EddsaPrivateKey.fromCrock(cd.coin.coinPriv))
.toCrock();
- let s: CoinPaySig = {
- coin_sig: coinSig,
+ const s: CoinPaySig = {
coin_pub: cd.coin.coinPub,
- ub_sig: cd.coin.denomSig,
+ coin_sig: coinSig,
denom_pub: cd.coin.denomPub,
f: coinSpend.toJson(),
+ ub_sig: cd.coin.denomSig,
};
ret.push({sig: s, updatedCoin: cd.coin});
}
@@ -290,7 +286,7 @@ namespace RpcFunctions {
let valueWithFee = Amounts.getZero(newCoinDenoms[0].value.currency);
- for (let ncd of newCoinDenoms) {
+ for (const ncd of newCoinDenoms) {
valueWithFee = Amounts.add(valueWithFee,
ncd.value,
ncd.feeWithdraw).amount;
@@ -299,23 +295,23 @@ namespace RpcFunctions {
// melt fee
valueWithFee = Amounts.add(valueWithFee, meltFee).amount;
- let sessionHc = new HashContext();
+ const sessionHc = new HashContext();
- let transferPubs: string[] = [];
- let transferPrivs: string[] = [];
+ const transferPubs: string[] = [];
+ const transferPrivs: string[] = [];
- let preCoinsForGammas: RefreshPreCoinRecord[][] = [];
+ const preCoinsForGammas: RefreshPreCoinRecord[][] = [];
for (let i = 0; i < kappa; i++) {
- let t = native.EcdhePrivateKey.create();
- let pub = t.getPublicKey();
+ const t = native.EcdhePrivateKey.create();
+ const pub = t.getPublicKey();
sessionHc.read(pub);
transferPrivs.push(t.toCrock());
transferPubs.push(pub.toCrock());
}
- for (let i = 0; i < newCoinDenoms.length; i++) {
- let r = native.RsaPublicKey.fromCrock(newCoinDenoms[i].denomPub);
+ for (const denom of newCoinDenoms) {
+ const r = native.RsaPublicKey.fromCrock(denom.denomPub);
sessionHc.read(r.encode());
}
@@ -323,31 +319,31 @@ namespace RpcFunctions {
sessionHc.read((new native.Amount(valueWithFee)).toNbo());
for (let i = 0; i < kappa; i++) {
- let preCoins: RefreshPreCoinRecord[] = [];
+ const preCoins: RefreshPreCoinRecord[] = [];
for (let j = 0; j < newCoinDenoms.length; j++) {
- let transferPriv = native.EcdhePrivateKey.fromCrock(transferPrivs[i]);
- let oldCoinPub = native.EddsaPublicKey.fromCrock(meltCoin.coinPub);
- let transferSecret = native.ecdhEddsa(transferPriv, oldCoinPub);
+ const transferPriv = native.EcdhePrivateKey.fromCrock(transferPrivs[i]);
+ const oldCoinPub = native.EddsaPublicKey.fromCrock(meltCoin.coinPub);
+ const transferSecret = native.ecdhEddsa(transferPriv, oldCoinPub);
- let fresh = native.setupFreshCoin(transferSecret, j);
+ const fresh = native.setupFreshCoin(transferSecret, j);
- let coinPriv = fresh.priv;
- let coinPub = coinPriv.getPublicKey();
- let blindingFactor = fresh.blindingKey;
- let pubHash: native.HashCode = coinPub.hash();
- let denomPub = native.RsaPublicKey.fromCrock(newCoinDenoms[j].denomPub);
- let ev = native.rsaBlind(pubHash,
+ const coinPriv = fresh.priv;
+ const coinPub = coinPriv.getPublicKey();
+ const blindingFactor = fresh.blindingKey;
+ const pubHash: native.HashCode = coinPub.hash();
+ const denomPub = native.RsaPublicKey.fromCrock(newCoinDenoms[j].denomPub);
+ const ev = native.rsaBlind(pubHash,
blindingFactor,
denomPub);
if (!ev) {
throw Error("couldn't blind (malicious exchange key?)");
}
- let preCoin: RefreshPreCoinRecord = {
+ const preCoin: RefreshPreCoinRecord = {
blindingKey: blindingFactor.toCrock(),
coinEv: ev.toCrock(),
- publicKey: coinPub.toCrock(),
privateKey: coinPriv.toCrock(),
+ publicKey: coinPub.toCrock(),
};
preCoins.push(preCoin);
sessionHc.read(ev);
@@ -355,40 +351,40 @@ namespace RpcFunctions {
preCoinsForGammas.push(preCoins);
}
- let sessionHash = new HashCode();
+ const sessionHash = new HashCode();
sessionHash.alloc();
sessionHc.finish(sessionHash);
- let confirmData = new RefreshMeltCoinAffirmationPS({
- coin_pub: EddsaPublicKey.fromCrock(meltCoin.coinPub),
+ const confirmData = new RefreshMeltCoinAffirmationPS({
amount_with_fee: (new Amount(valueWithFee)).toNbo(),
+ coin_pub: EddsaPublicKey.fromCrock(meltCoin.coinPub),
+ melt_fee: (new Amount(meltFee)).toNbo(),
session_hash: sessionHash,
- melt_fee: (new Amount(meltFee)).toNbo()
});
- let confirmSig: string = native.eddsaSign(confirmData.toPurpose(),
+ const confirmSig: string = native.eddsaSign(confirmData.toPurpose(),
native.EddsaPrivateKey.fromCrock(
meltCoin.coinPriv)).toCrock();
let valueOutput = Amounts.getZero(newCoinDenoms[0].value.currency);
- for (let denom of newCoinDenoms) {
+ for (const denom of newCoinDenoms) {
valueOutput = Amounts.add(valueOutput, denom.value).amount;
}
- let refreshSession: RefreshSessionRecord = {
- meltCoinPub: meltCoin.coinPub,
- newDenoms: newCoinDenoms.map((d) => d.denomPub),
+ const refreshSession: RefreshSessionRecord = {
confirmSig,
- valueWithFee,
- transferPubs,
- preCoinsForGammas,
+ exchangeBaseUrl,
+ finished: false,
hash: sessionHash.toCrock(),
+ meltCoinPub: meltCoin.coinPub,
+ newDenoms: newCoinDenoms.map((d) => d.denomPub),
norevealIndex: undefined,
- exchangeBaseUrl,
+ preCoinsForGammas,
transferPrivs,
- finished: false,
+ transferPubs,
valueOutput,
+ valueWithFee,
};
return refreshSession;
@@ -408,24 +404,24 @@ namespace RpcFunctions {
}
-let worker: Worker = (self as any) as Worker;
+const worker: Worker = (self as any) as Worker;
worker.onmessage = (msg: MessageEvent) => {
if (!Array.isArray(msg.data.args)) {
console.error("args must be array");
return;
}
- if (typeof msg.data.id != "number") {
+ if (typeof msg.data.id !== "number") {
console.error("RPC id must be number");
}
- if (typeof msg.data.operation != "string") {
+ if (typeof msg.data.operation !== "string") {
console.error("RPC operation must be string");
}
- let f = (RpcFunctions as any)[msg.data.operation];
+ const f = (RpcFunctions as any)[msg.data.operation];
if (!f) {
console.error(`unknown operation: '${msg.data.operation}'`);
return;
}
- let res = f(...msg.data.args);
+ const res = f(...msg.data.args);
worker.postMessage({result: res, id: msg.data.id});
-}
+};
diff --git a/src/crypto/emscInterface-test.ts b/src/crypto/emscInterface-test.ts
index dc98308fb..789ac2509 100644
--- a/src/crypto/emscInterface-test.ts
+++ b/src/crypto/emscInterface-test.ts
@@ -1,101 +1,124 @@
+/*
+ This file is part of TALER
+ (C) 2017 Inria and 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, see <http://www.gnu.org/licenses/>
+ */
+
+// tslint:disable:max-line-length
+
import {test} from "ava";
import * as native from "./emscInterface";
-test("string hashing", t => {
- let x = native.ByteArray.fromStringWithNull("hello taler");
- let h = "8RDMADB3YNF3QZBS3V467YZVJAMC2QAQX0TZGVZ6Q5PFRRAJFT70HHN0QF661QR9QWKYMMC7YEMPD679D2RADXCYK8Y669A2A5MKQFR"
- let hc = x.hash().toCrock();
+test("string hashing", (t) => {
+ const x = native.ByteArray.fromStringWithNull("hello taler");
+ const h = "8RDMADB3YNF3QZBS3V467YZVJAMC2QAQX0TZGVZ6Q5PFRRAJFT70HHN0QF661QR9QWKYMMC7YEMPD679D2RADXCYK8Y669A2A5MKQFR";
+ const hc = x.hash().toCrock();
console.log(`# hc ${hc}`);
t.true(h === hc, "must equal");
t.pass();
});
-test("signing", t => {
- let x = native.ByteArray.fromStringWithNull("hello taler");
- let priv = native.EddsaPrivateKey.create();
- let pub = priv.getPublicKey();
- let purpose = new native.EccSignaturePurpose(native.SignaturePurpose.TEST, x);
- let sig = native.eddsaSign(purpose, priv);
+
+test("signing", (t) => {
+ const x = native.ByteArray.fromStringWithNull("hello taler");
+ const priv = native.EddsaPrivateKey.create();
+ const pub = priv.getPublicKey();
+ const purpose = new native.EccSignaturePurpose(native.SignaturePurpose.TEST, x);
+ const sig = native.eddsaSign(purpose, priv);
t.true(native.eddsaVerify(native.SignaturePurpose.TEST, purpose, sig, pub));
t.pass();
});
-test("signing-fixed-data", t => {
- let x = native.ByteArray.fromStringWithNull("hello taler");
- let purpose = new native.EccSignaturePurpose(native.SignaturePurpose.TEST, x);
+
+test("signing-fixed-data", (t) => {
+ const x = native.ByteArray.fromStringWithNull("hello taler");
+ const purpose = new native.EccSignaturePurpose(native.SignaturePurpose.TEST, x);
const privStr = "G9R8KRRCAFKPD0KW7PW48CC2T03VQ8K2AN9J6J6K2YW27J5MHN90";
const pubStr = "YHCZB442FQFJ0ET20MWA8YJ53M61EZGJ6QKV1KTJZMRNXDY45WT0";
const sigStr = "7V6XY4QGC1406GPMT305MZQ1HDCR7R0S5BP02GTGDQFPSXB6YD2YDN5ZS7NJQCNP61Y39MRHXNXQ1Z15JY4CJY4CPDA6CKQ3313WG38";
- let priv = native.EddsaPrivateKey.fromCrock(privStr);
- t.true(privStr == priv.toCrock())
- let pub = priv.getPublicKey();
- t.true(pubStr == pub.toCrock());
- let sig = native.EddsaSignature.fromCrock(sigStr);
- t.true(sigStr == sig.toCrock())
- let sig2 = native.eddsaSign(purpose, priv);
- t.true(sig.toCrock() == sig2.toCrock());
+ const priv = native.EddsaPrivateKey.fromCrock(privStr);
+ t.true(privStr === priv.toCrock());
+ const pub = priv.getPublicKey();
+ t.true(pubStr === pub.toCrock());
+ const sig = native.EddsaSignature.fromCrock(sigStr);
+ t.true(sigStr === sig.toCrock());
+ const sig2 = native.eddsaSign(purpose, priv);
+ t.true(sig.toCrock() === sig2.toCrock());
t.true(native.eddsaVerify(native.SignaturePurpose.TEST, purpose, sig, pub));
t.pass();
});
+
const denomPubStr1 = "51R7ARKCD5HJTTV5F4G0M818E9SP280A40G2GVH04CR30G9R64VK6HHS6MW42DSN8MVKJGHK6WR3CGT18MWMCDSM75138E1K8S0MADSQ68W34DHH6MW4CHA270W4CG9J6GW48DHG8MVK4E9S7523GEA56H0K4E1Q891KCCSG752KGC1M88VMCDSQ6D23CHHG8H33AGHG6MSK8GT26CRKAC1M64V3JCJ56CVKCC228MWMCHA26MS30H1J8MVKEDHJ70TMADHK892KJC1H60TKJDHM710KGGT584T38H9K851KCDHG60W30HJ28CT4CC1G8CR3JGJ28H236DJ28H330H9S890M2D9S8S14AGA369344GA36S248CHS70RKEDSS6MWKGDJ26D136GT465348CSS8S232CHM6GS34C9N8CS3GD9H60W36H1R8MSK2GSQ8MSM6C9R70SKCHHN6MW3ACJ28N0K2CA58RS3GCA26MV42G9P891KAG9Q8N0KGD9M850KEHJ16S130CA27124AE1G852KJCHR6S1KGDSJ8RTKED1S8RR3CCHP68W4CH9Q6GT34GT18GS36EA46N24AGSP6933GCHM60VMAE1S8GV3EHHN74W3GC1J651KEH9N8MSK0CSG6S2KEEA460R32C1M8D144GSR6RWKEC218S0KEGJ4611KEEA36CSKJC2564TM4CSJ6H230E1N74TM8C1P61342CSG60WKCGHH64VK2G9S8CRKAHHK88W30HJ388R3CH1Q6X2K2DHK8GSM4D1Q74WM4HA461146H9S6D33JDJ26D234C9Q6923ECSS60RM6CT46CSKCH1M6S13EH9J8S33GCSN4CMGM81051JJ08SG64R30C1H4CMGM81054520A8A00";
-test("rsa-encode", t => {
- const pubHashStr = "JM63YM5X7X547164QJ3MGJZ4WDD47GEQR5DW5SH35G4JFZXEJBHE5JBNZM5K8XN5C4BRW25BE6GSVAYBF790G2BZZ13VW91D41S4DS0"
- let denomPub = native.RsaPublicKey.fromCrock(denomPubStr1);
- let pubHash = denomPub.encode().hash();
- t.true(pubHashStr == pubHash.toCrock());
+
+test("rsa-encode", (t) => {
+ const pubHashStr = "JM63YM5X7X547164QJ3MGJZ4WDD47GEQR5DW5SH35G4JFZXEJBHE5JBNZM5K8XN5C4BRW25BE6GSVAYBF790G2BZZ13VW91D41S4DS0";
+ const denomPub = native.RsaPublicKey.fromCrock(denomPubStr1);
+ const pubHash = denomPub.encode().hash();
+ t.true(pubHashStr === pubHash.toCrock());
t.pass();
});
-test("withdraw-request", t => {
+test("withdraw-request", (t) => {
const reservePrivStr = "G9R8KRRCAFKPD0KW7PW48CC2T03VQ8K2AN9J6J6K2YW27J5MHN90";
const reservePriv = native.EddsaPrivateKey.fromCrock(reservePrivStr);
const reservePub = reservePriv.getPublicKey();
const amountWithFee = new native.Amount({currency: "KUDOS", value: 1, fraction: 10000});
amountWithFee.add(new native.Amount({currency: "KUDOS", value: 0, fraction: 20000}));
- const withdrawFee = new native.Amount({currency: "KUDOS", value: 0, fraction: 20000})
+ const withdrawFee = new native.Amount({currency: "KUDOS", value: 0, fraction: 20000});
const denomPub = native.RsaPublicKey.fromCrock(denomPubStr1);
const ev = native.ByteArray.fromStringWithNull("hello, world");
-
// Signature
- let withdrawRequest = new native.WithdrawRequestPS({
- reserve_pub: reservePub,
+ const withdrawRequest = new native.WithdrawRequestPS({
amount_with_fee: amountWithFee.toNbo(),
- withdraw_fee: withdrawFee.toNbo(),
+ h_coin_envelope: ev.hash(),
h_denomination_pub: denomPub.encode().hash(),
- h_coin_envelope: ev.hash()
+ reserve_pub: reservePub,
+ withdraw_fee: withdrawFee.toNbo(),
});
- var sigStr = "AD3T8W44NV193J19RAN3NAJHPP6RVB0R3NWV7ZK5G8Q946YDK0B6F8YJBNRRBXSPVTKY31S7BVZPJFFTJJRMY61DH51X4JSXK677428";
+ const sigStr = "AD3T8W44NV193J19RAN3NAJHPP6RVB0R3NWV7ZK5G8Q946YDK0B6F8YJBNRRBXSPVTKY31S7BVZPJFFTJJRMY61DH51X4JSXK677428";
- var sig = native.eddsaSign(withdrawRequest.toPurpose(), reservePriv);
+ const sig = native.eddsaSign(withdrawRequest.toPurpose(), reservePriv);
t.true(native.eddsaVerify(native.SignaturePurpose.RESERVE_WITHDRAW, withdrawRequest.toPurpose(), sig, reservePub));
- t.true(sig.toCrock() == sigStr);
+ t.true(sig.toCrock() === sigStr);
t.pass();
});
-test("withdraw-request", t => {
+
+test("withdraw-request", (t) => {
const a1 = new native.Amount({currency: "KUDOS", value: 1, fraction: 50000000});
const a2 = new native.Amount({currency: "KUDOS", value: 1, fraction: 50000000});
a1.add(a2);
- let x = a1.toJson();
- t.true(x.currency == "KUDOS");
- t.true(x.fraction == 0);
- t.true(x.value == 3);
+ const x = a1.toJson();
+ t.true(x.currency === "KUDOS");
+ t.true(x.fraction === 0);
+ t.true(x.value === 3);
t.pass();
});
-test("ecdsa", t => {
+test("ecdsa", (t) => {
const priv = native.EcdsaPrivateKey.create();
const pub1 = priv.getPublicKey();
t.pass();
});
-test("ecdhe", t => {
+
+test("ecdhe", (t) => {
const priv = native.EcdhePrivateKey.create();
const pub = priv.getPublicKey();
t.pass();
diff --git a/src/crypto/emscInterface.ts b/src/crypto/emscInterface.ts
index 52c6c965e..e00e67a84 100644
--- a/src/crypto/emscInterface.ts
+++ b/src/crypto/emscInterface.ts
@@ -27,8 +27,8 @@
* Imports.
*/
import {AmountJson} from "../types";
-import {getLib, EmscFunGen} from "./emscLoader";
+import {EmscFunGen, getLib} from "./emscLoader";
const emscLib = getLib();
@@ -51,7 +51,7 @@ const GNUNET_SYSERR = -1;
const getEmsc: EmscFunGen = (name: string, ret: any, argTypes: any[]) => {
return (...args: any[]) => {
return emscLib.ccall(name, ret, argTypes, args);
- }
+ };
};
@@ -59,84 +59,32 @@ const getEmsc: EmscFunGen = (name: string, ret: any, argTypes: any[]) => {
* Wrapped emscripten functions that do not allocate any memory.
*/
const emsc = {
+ amount_add: getEmsc("TALER_amount_add", "number", ["number", "number", "number"]),
+ amount_cmp: getEmsc("TALER_amount_cmp", "number", ["number", "number"]),
+ amount_get_zero: getEmsc("TALER_amount_get_zero", "number", ["string", "number"]),
+ amount_hton: getEmsc("TALER_amount_hton", "void", ["number", "number"]),
+ amount_normalize: getEmsc("TALER_amount_normalize", "void", ["number"]),
+ amount_ntoh: getEmsc("TALER_amount_ntoh", "void", ["number", "number"]),
+ amount_subtract: getEmsc("TALER_amount_subtract", "number", ["number", "number", "number"]),
+ ecdh_eddsa: getEmsc("GNUNET_CRYPTO_ecdh_eddsa", "number", ["number", "number", "number"]),
+ eddsa_sign: getEmsc("GNUNET_CRYPTO_eddsa_sign", "number", ["number", "number", "number"]),
+ eddsa_verify: getEmsc("GNUNET_CRYPTO_eddsa_verify", "number", ["number", "number", "number", "number"]),
free: (ptr: number) => emscLib._free(ptr),
- get_value: getEmsc("TALER_WR_get_value",
- "number",
- ["number"]),
- get_fraction: getEmsc("TALER_WR_get_fraction",
- "number",
- ["number"]),
- get_currency: getEmsc("TALER_WR_get_currency",
- "string",
- ["number"]),
- amount_add: getEmsc("TALER_amount_add",
- "number",
- ["number", "number", "number"]),
- amount_subtract: getEmsc("TALER_amount_subtract",
- "number",
- ["number", "number", "number"]),
- amount_normalize: getEmsc("TALER_amount_normalize",
- "void",
- ["number"]),
- amount_get_zero: getEmsc("TALER_amount_get_zero",
- "number",
- ["string", "number"]),
- amount_cmp: getEmsc("TALER_amount_cmp",
- "number",
- ["number", "number"]),
- amount_hton: getEmsc("TALER_amount_hton",
- "void",
- ["number", "number"]),
- amount_ntoh: getEmsc("TALER_amount_ntoh",
- "void",
- ["number", "number"]),
- hash: getEmsc("GNUNET_CRYPTO_hash",
- "void",
- ["number", "number", "number"]),
- memmove: getEmsc("memmove",
- "number",
- ["number", "number", "number"]),
- rsa_public_key_free: getEmsc("GNUNET_CRYPTO_rsa_public_key_free",
- "void",
- ["number"]),
- rsa_signature_free: getEmsc("GNUNET_CRYPTO_rsa_signature_free",
- "void",
- ["number"]),
- string_to_data: getEmsc("GNUNET_STRINGS_string_to_data",
- "number",
- ["number", "number", "number", "number"]),
- eddsa_sign: getEmsc("GNUNET_CRYPTO_eddsa_sign",
- "number",
- ["number", "number", "number"]),
- eddsa_verify: getEmsc("GNUNET_CRYPTO_eddsa_verify",
- "number",
- ["number", "number", "number", "number"]),
- hash_create_random: getEmsc("GNUNET_CRYPTO_hash_create_random",
- "void",
- ["number", "number"]),
- rsa_blinding_key_destroy: getEmsc("GNUNET_CRYPTO_rsa_blinding_key_free",
- "void",
- ["number"]),
- random_block: getEmsc("GNUNET_CRYPTO_random_block",
- "void",
- ["number", "number", "number"]),
- hash_context_abort: getEmsc("GNUNET_CRYPTO_hash_context_abort",
- "void",
- ["number"]),
- hash_context_read: getEmsc("GNUNET_CRYPTO_hash_context_read",
- "void",
- ["number", "number", "number"]),
- hash_context_finish: getEmsc("GNUNET_CRYPTO_hash_context_finish",
- "void",
- ["number", "number"]),
- ecdh_eddsa: getEmsc("GNUNET_CRYPTO_ecdh_eddsa",
- "number",
- ["number", "number", "number"]),
-
- setup_fresh_coin: getEmsc(
- "TALER_setup_fresh_coin",
- "void",
- ["number", "number", "number"]),
+ get_currency: getEmsc("TALER_WR_get_currency", "string", ["number"]),
+ get_fraction: getEmsc("TALER_WR_get_fraction", "number", ["number"]),
+ get_value: getEmsc("TALER_WR_get_value", "number", ["number"]),
+ hash: getEmsc("GNUNET_CRYPTO_hash", "void", ["number", "number", "number"]),
+ hash_context_abort: getEmsc("GNUNET_CRYPTO_hash_context_abort", "void", ["number"]),
+ hash_context_finish: getEmsc("GNUNET_CRYPTO_hash_context_finish", "void", ["number", "number"]),
+ hash_context_read: getEmsc("GNUNET_CRYPTO_hash_context_read", "void", ["number", "number", "number"]),
+ hash_create_random: getEmsc("GNUNET_CRYPTO_hash_create_random", "void", ["number", "number"]),
+ memmove: getEmsc("memmove", "number", ["number", "number", "number"]),
+ random_block: getEmsc("GNUNET_CRYPTO_random_block", "void", ["number", "number", "number"]),
+ rsa_blinding_key_destroy: getEmsc("GNUNET_CRYPTO_rsa_blinding_key_free", "void", ["number"]),
+ rsa_public_key_free: getEmsc("GNUNET_CRYPTO_rsa_public_key_free", "void", ["number"]),
+ rsa_signature_free: getEmsc("GNUNET_CRYPTO_rsa_signature_free", "void", ["number"]),
+ setup_fresh_coin: getEmsc( "TALER_setup_fresh_coin", "void", ["number", "number", "number"]),
+ string_to_data: getEmsc("GNUNET_STRINGS_string_to_data", "number", ["number", "number", "number", "number"]),
};
@@ -144,64 +92,26 @@ const emsc = {
* Emscripten functions that allocate memory.
*/
const emscAlloc = {
- get_amount: getEmsc("TALER_WRALL_get_amount",
- "number",
- ["number", "number", "number", "string"]),
- eddsa_key_create: getEmsc("GNUNET_CRYPTO_eddsa_key_create",
- "number", []),
- ecdsa_key_create: getEmsc("GNUNET_CRYPTO_ecdsa_key_create",
- "number", []),
- ecdhe_key_create: getEmsc("GNUNET_CRYPTO_ecdhe_key_create",
- "number", []),
- eddsa_public_key_from_private: getEmsc(
- "TALER_WRALL_eddsa_public_key_from_private",
- "number",
- ["number"]),
- ecdsa_public_key_from_private: getEmsc(
- "TALER_WRALL_ecdsa_public_key_from_private",
- "number",
- ["number"]),
- ecdhe_public_key_from_private: getEmsc(
- "TALER_WRALL_ecdhe_public_key_from_private",
- "number",
- ["number"]),
- data_to_string_alloc: getEmsc("GNUNET_STRINGS_data_to_string_alloc",
- "number",
- ["number", "number"]),
- purpose_create: getEmsc("TALER_WRALL_purpose_create",
- "number",
- ["number", "number", "number"]),
- rsa_blind: getEmsc("GNUNET_CRYPTO_rsa_blind",
- "number",
- ["number", "number", "number", "number", "number"]),
- rsa_blinding_key_create: getEmsc("GNUNET_CRYPTO_rsa_blinding_key_create",
- "number",
- ["number"]),
- rsa_blinding_key_encode: getEmsc("GNUNET_CRYPTO_rsa_blinding_key_encode",
- "number",
- ["number", "number"]),
- rsa_signature_encode: getEmsc("GNUNET_CRYPTO_rsa_signature_encode",
- "number",
- ["number", "number"]),
- rsa_blinding_key_decode: getEmsc("GNUNET_CRYPTO_rsa_blinding_key_decode",
- "number",
- ["number", "number"]),
- rsa_public_key_decode: getEmsc("GNUNET_CRYPTO_rsa_public_key_decode",
- "number",
- ["number", "number"]),
- rsa_signature_decode: getEmsc("GNUNET_CRYPTO_rsa_signature_decode",
- "number",
- ["number", "number"]),
- rsa_public_key_encode: getEmsc("GNUNET_CRYPTO_rsa_public_key_encode",
- "number",
- ["number", "number"]),
- rsa_unblind: getEmsc("GNUNET_CRYPTO_rsa_unblind",
- "number",
- ["number", "number", "number"]),
- hash_context_start: getEmsc("GNUNET_CRYPTO_hash_context_start",
- "number",
- []),
+ data_to_string_alloc: getEmsc("GNUNET_STRINGS_data_to_string_alloc", "number", ["number", "number"]),
+ ecdhe_key_create: getEmsc("GNUNET_CRYPTO_ecdhe_key_create", "number", []),
+ ecdhe_public_key_from_private: getEmsc( "TALER_WRALL_ecdhe_public_key_from_private", "number", ["number"]),
+ ecdsa_key_create: getEmsc("GNUNET_CRYPTO_ecdsa_key_create", "number", []),
+ ecdsa_public_key_from_private: getEmsc( "TALER_WRALL_ecdsa_public_key_from_private", "number", ["number"]),
+ eddsa_key_create: getEmsc("GNUNET_CRYPTO_eddsa_key_create", "number", []),
+ eddsa_public_key_from_private: getEmsc( "TALER_WRALL_eddsa_public_key_from_private", "number", ["number"]),
+ get_amount: getEmsc("TALER_WRALL_get_amount", "number", ["number", "number", "number", "string"]),
+ hash_context_start: getEmsc("GNUNET_CRYPTO_hash_context_start", "number", []),
malloc: (size: number) => emscLib._malloc(size),
+ purpose_create: getEmsc("TALER_WRALL_purpose_create", "number", ["number", "number", "number"]),
+ rsa_blind: getEmsc("GNUNET_CRYPTO_rsa_blind", "number", ["number", "number", "number", "number", "number"]),
+ rsa_blinding_key_create: getEmsc("GNUNET_CRYPTO_rsa_blinding_key_create", "number", ["number"]),
+ rsa_blinding_key_decode: getEmsc("GNUNET_CRYPTO_rsa_blinding_key_decode", "number", ["number", "number"]),
+ rsa_blinding_key_encode: getEmsc("GNUNET_CRYPTO_rsa_blinding_key_encode", "number", ["number", "number"]),
+ rsa_public_key_decode: getEmsc("GNUNET_CRYPTO_rsa_public_key_decode", "number", ["number", "number"]),
+ rsa_public_key_encode: getEmsc("GNUNET_CRYPTO_rsa_public_key_encode", "number", ["number", "number"]),
+ rsa_signature_decode: getEmsc("GNUNET_CRYPTO_rsa_signature_decode", "number", ["number", "number"]),
+ rsa_signature_encode: getEmsc("GNUNET_CRYPTO_rsa_signature_encode", "number", ["number", "number"]),
+ rsa_unblind: getEmsc("GNUNET_CRYPTO_rsa_unblind", "number", ["number", "number", "number"]),
};
@@ -226,7 +136,7 @@ export enum SignaturePurpose {
export enum RandomQuality {
WEAK = 0,
STRONG = 1,
- NONCE = 2
+ NONCE = 2,
}
@@ -301,8 +211,8 @@ abstract class MallocArenaObject implements ArenaObject {
constructor(arena?: Arena) {
if (!arena) {
- if (arenaStack.length == 0) {
- throw Error("No arena available")
+ if (arenaStack.length === 0) {
+ throw Error("No arena available");
}
arena = arenaStack[arenaStack.length - 1];
}
@@ -349,7 +259,7 @@ interface Arena {
* Arena that must be manually destroyed.
*/
class SimpleArena implements Arena {
- heap: Array<ArenaObject>;
+ heap: ArenaObject[];
constructor() {
this.heap = [];
@@ -360,10 +270,10 @@ class SimpleArena implements Arena {
}
destroy() {
- for (let obj of this.heap) {
+ for (const obj of this.heap) {
obj.destroy();
}
- this.heap = []
+ this.heap = [];
}
}
@@ -396,7 +306,7 @@ class SyncArena extends SimpleArena {
}
}
-let arenaStack: Arena[] = [];
+const arenaStack: Arena[] = [];
arenaStack.push(new SyncArena());
@@ -417,9 +327,9 @@ export class Amount extends MallocArenaObject {
}
static getZero(currency: string, a?: Arena): Amount {
- let am = new Amount(undefined, a);
- let r = emsc.amount_get_zero(currency, am.nativePtr);
- if (r != GNUNET_OK) {
+ const am = new Amount(undefined, a);
+ const r = emsc.amount_get_zero(currency, am.nativePtr);
+ if (r !== GNUNET_OK) {
throw Error("invalid currency");
}
return am;
@@ -427,7 +337,7 @@ export class Amount extends MallocArenaObject {
toNbo(a?: Arena): AmountNbo {
- let x = new AmountNbo(a);
+ const x = new AmountNbo(a);
x.alloc();
emsc.amount_hton(x.nativePtr, this.nativePtr);
return x;
@@ -445,15 +355,15 @@ export class Amount extends MallocArenaObject {
return emsc.get_fraction(this.nativePtr);
}
- get currency(): String {
+ get currency(): string {
return emsc.get_currency(this.nativePtr);
}
toJson(): AmountJson {
return {
- value: emsc.get_value(this.nativePtr),
+ currency: emsc.get_currency(this.nativePtr),
fraction: emsc.get_fraction(this.nativePtr),
- currency: emsc.get_currency(this.nativePtr)
+ value: emsc.get_value(this.nativePtr),
};
}
@@ -461,7 +371,7 @@ export class Amount extends MallocArenaObject {
* Add an amount to this amount.
*/
add(a: Amount) {
- let res = emsc.amount_add(this.nativePtr, a.nativePtr, this.nativePtr);
+ const res = emsc.amount_add(this.nativePtr, a.nativePtr, this.nativePtr);
if (res < 1) {
// Overflow
return false;
@@ -474,8 +384,8 @@ export class Amount extends MallocArenaObject {
*/
sub(a: Amount) {
// this = this - a
- let res = emsc.amount_subtract(this.nativePtr, this.nativePtr, a.nativePtr);
- if (res == 0) {
+ const res = emsc.amount_subtract(this.nativePtr, this.nativePtr, a.nativePtr);
+ if (res === 0) {
// Underflow
return false;
}
@@ -503,10 +413,10 @@ export class Amount extends MallocArenaObject {
* Count the UTF-8 characters in a JavaScript string.
*/
function countUtf8Bytes(str: string): number {
- var s = str.length;
+ let s = str.length;
// JavaScript strings are UTF-16 arrays
for (let i = str.length - 1; i >= 0; i--) {
- var code = str.charCodeAt(i);
+ const code = str.charCodeAt(i);
if (code > 0x7f && code <= 0x7ff) {
// We need an extra byte in utf-8 here
s++;
@@ -540,8 +450,8 @@ abstract class PackedArenaObject extends MallocArenaObject {
}
toCrock(): string {
- var d = emscAlloc.data_to_string_alloc(this.nativePtr, this.size());
- var s = emscLib.Pointer_stringify(d);
+ const d = emscAlloc.data_to_string_alloc(this.nativePtr, this.size());
+ const s = emscLib.Pointer_stringify(d);
emsc.free(d);
return s;
}
@@ -557,8 +467,8 @@ abstract class PackedArenaObject extends MallocArenaObject {
this.alloc();
// We need to get the javascript string
// to the emscripten heap first.
- let buf = ByteArray.fromStringWithNull(s);
- let res = emsc.string_to_data(buf.nativePtr,
+ const buf = ByteArray.fromStringWithNull(s);
+ const res = emsc.string_to_data(buf.nativePtr,
s.length,
this.nativePtr,
this.size());
@@ -576,20 +486,20 @@ abstract class PackedArenaObject extends MallocArenaObject {
}
hash(): HashCode {
- var x = new HashCode();
+ const x = new HashCode();
x.alloc();
emsc.hash(this.nativePtr, this.size(), x.nativePtr);
return x;
}
hexdump() {
- let bytes: string[] = [];
+ const bytes: string[] = [];
for (let i = 0; i < this.size(); i++) {
let b = emscLib.getValue(this.nativePtr + i, "i8");
b = (b + 256) % 256;
bytes.push("0".concat(b.toString(16)).slice(-2));
}
- let lines: string[] = [];
+ const lines: string[] = [];
for (let i = 0; i < bytes.length; i += 8) {
lines.push(bytes.slice(i, i + 8).join(","));
}
@@ -607,10 +517,10 @@ export class AmountNbo extends PackedArenaObject {
}
toJson(): any {
- let a = new SimpleArena();
- let am = new Amount(undefined, a);
+ const a = new SimpleArena();
+ const am = new Amount(undefined, a);
am.fromNbo(this);
- let json = am.toJson();
+ const json = am.toJson();
a.destroy();
return json;
}
@@ -621,7 +531,7 @@ export class AmountNbo extends PackedArenaObject {
* Create a packed arena object from the base32 crockford encoding.
*/
function fromCrock<T extends PackedArenaObject>(s: string, ctor: Ctor<T>): T {
- let x: T = new ctor();
+ const x: T = new ctor();
x.alloc();
x.loadCrock(s);
return x;
@@ -632,9 +542,11 @@ function fromCrock<T extends PackedArenaObject>(s: string, ctor: Ctor<T>): T {
* Create a packed arena object from the base32 crockford encoding for objects
* that have a special decoding function.
*/
-function fromCrockDecoded<T extends MallocArenaObject>(s: string, ctor: Ctor<T>, decodeFn: (p: number, s: number) => number): T {
- let obj = new ctor();
- let buf = ByteArray.fromCrock(s);
+function fromCrockDecoded<T extends MallocArenaObject>(s: string,
+ ctor: Ctor<T>,
+ decodeFn: (p: number, s: number) => number): T {
+ const obj = new ctor();
+ const buf = ByteArray.fromCrock(s);
obj.nativePtr = decodeFn(buf.nativePtr, buf.size());
buf.destroy();
return obj;
@@ -645,10 +557,10 @@ function fromCrockDecoded<T extends MallocArenaObject>(s: string, ctor: Ctor<T>,
* Encode an object using a special encoding function.
*/
function encode<T extends MallocArenaObject>(obj: T, encodeFn: any, arena?: Arena): ByteArray {
- let ptr = emscAlloc.malloc(PTR_SIZE);
- let len = encodeFn(obj.nativePtr, ptr);
- let res = new ByteArray(len, undefined, arena);
- res.nativePtr = emscLib.getValue(ptr, '*');
+ const ptr = emscAlloc.malloc(PTR_SIZE);
+ const len = encodeFn(obj.nativePtr, ptr);
+ const res = new ByteArray(len, undefined, arena);
+ res.nativePtr = emscLib.getValue(ptr, "*");
emsc.free(ptr);
return res;
}
@@ -659,7 +571,7 @@ function encode<T extends MallocArenaObject>(obj: T, encodeFn: any, arena?: Aren
*/
export class EddsaPrivateKey extends PackedArenaObject {
static create(a?: Arena): EddsaPrivateKey {
- let obj = new EddsaPrivateKey(a);
+ const obj = new EddsaPrivateKey(a);
obj.nativePtr = emscAlloc.eddsa_key_create();
return obj;
}
@@ -669,7 +581,7 @@ export class EddsaPrivateKey extends PackedArenaObject {
}
getPublicKey(a?: Arena): EddsaPublicKey {
- let obj = new EddsaPublicKey(a);
+ const obj = new EddsaPublicKey(a);
obj.nativePtr = emscAlloc.eddsa_public_key_from_private(this.nativePtr);
return obj;
}
@@ -682,7 +594,7 @@ export class EddsaPrivateKey extends PackedArenaObject {
export class EcdsaPrivateKey extends PackedArenaObject {
static create(a?: Arena): EcdsaPrivateKey {
- let obj = new EcdsaPrivateKey(a);
+ const obj = new EcdsaPrivateKey(a);
obj.nativePtr = emscAlloc.ecdsa_key_create();
return obj;
}
@@ -692,7 +604,7 @@ export class EcdsaPrivateKey extends PackedArenaObject {
}
getPublicKey(a?: Arena): EcdsaPublicKey {
- let obj = new EcdsaPublicKey(a);
+ const obj = new EcdsaPublicKey(a);
obj.nativePtr = emscAlloc.ecdsa_public_key_from_private(this.nativePtr);
return obj;
}
@@ -705,7 +617,7 @@ export class EcdsaPrivateKey extends PackedArenaObject {
export class EcdhePrivateKey extends PackedArenaObject {
static create(a?: Arena): EcdhePrivateKey {
- let obj = new EcdhePrivateKey(a);
+ const obj = new EcdhePrivateKey(a);
obj.nativePtr = emscAlloc.ecdhe_key_create();
return obj;
}
@@ -715,7 +627,7 @@ export class EcdhePrivateKey extends PackedArenaObject {
}
getPublicKey(a?: Arena): EcdhePublicKey {
- let obj = new EcdhePublicKey(a);
+ const obj = new EcdhePublicKey(a);
obj.nativePtr = emscAlloc.ecdhe_public_key_from_private(this.nativePtr);
return obj;
}
@@ -730,7 +642,7 @@ export class EcdhePrivateKey extends PackedArenaObject {
* Constructor for a given type.
*/
interface Ctor<T> {
- new(): T
+ new(): T;
}
@@ -774,7 +686,7 @@ export class RsaBlindingKeySecret extends PackedArenaObject {
* Create a random blinding key secret.
*/
static create(a?: Arena): RsaBlindingKeySecret {
- let o = new RsaBlindingKeySecret(a);
+ const o = new RsaBlindingKeySecret(a);
o.alloc();
o.randomize();
return o;
@@ -821,16 +733,16 @@ export class ByteArray extends PackedArenaObject {
static fromStringWithoutNull(s: string, a?: Arena): ByteArray {
// UTF-8 bytes, including 0-terminator
- let terminatedByteLength = countUtf8Bytes(s) + 1;
- let hstr = emscAlloc.malloc(terminatedByteLength);
+ const terminatedByteLength = countUtf8Bytes(s) + 1;
+ const hstr = emscAlloc.malloc(terminatedByteLength);
emscLib.stringToUTF8(s, hstr, terminatedByteLength);
return new ByteArray(terminatedByteLength - 1, hstr, a);
}
static fromStringWithNull(s: string, a?: Arena): ByteArray {
// UTF-8 bytes, including 0-terminator
- let terminatedByteLength = countUtf8Bytes(s) + 1;
- let hstr = emscAlloc.malloc(terminatedByteLength);
+ const terminatedByteLength = countUtf8Bytes(s) + 1;
+ const hstr = emscAlloc.malloc(terminatedByteLength);
emscLib.stringToUTF8(s, hstr, terminatedByteLength);
return new ByteArray(terminatedByteLength, hstr, a);
}
@@ -838,14 +750,14 @@ export class ByteArray extends PackedArenaObject {
static fromCrock(s: string, a?: Arena): ByteArray {
// this one is a bit more complicated than the other fromCrock functions,
// since we don't have a fixed size
- let byteLength = countUtf8Bytes(s);
- let hstr = emscAlloc.malloc(byteLength + 1);
+ const byteLength = countUtf8Bytes(s);
+ const hstr = emscAlloc.malloc(byteLength + 1);
emscLib.stringToUTF8(s, hstr, byteLength + 1);
- let decodedLen = Math.floor((byteLength * 5) / 8);
- let ba = new ByteArray(decodedLen, undefined, a);
- let res = emsc.string_to_data(hstr, byteLength, ba.nativePtr, decodedLen);
+ const decodedLen = Math.floor((byteLength * 5) / 8);
+ const ba = new ByteArray(decodedLen, undefined, a);
+ const res = emsc.string_to_data(hstr, byteLength, ba.nativePtr, decodedLen);
emsc.free(hstr);
- if (res != GNUNET_OK) {
+ if (res !== GNUNET_OK) {
throw Error("decoding failed");
}
return ba;
@@ -877,60 +789,60 @@ export class EccSignaturePurpose extends PackedArenaObject {
abstract class SignatureStruct {
- abstract fieldTypes(): Array<any>;
+ abstract fieldTypes(): any[];
abstract purpose(): SignaturePurpose;
private members: any = {};
constructor(x: { [name: string]: any }) {
- for (let k in x) {
+ for (const k in x) {
this.set(k, x[k]);
}
}
toPurpose(a?: Arena): EccSignaturePurpose {
let totalSize = 0;
- for (let f of this.fieldTypes()) {
- let name = f[0];
- let member = this.members[name];
+ for (const f of this.fieldTypes()) {
+ const name = f[0];
+ const member = this.members[name];
if (!member) {
throw Error(`Member ${name} not set`);
}
totalSize += member.size();
}
- let buf = emscAlloc.malloc(totalSize);
+ const buf = emscAlloc.malloc(totalSize);
let ptr = buf;
- for (let f of this.fieldTypes()) {
- let name = f[0];
- let member = this.members[name];
- let size = member.size();
+ for (const f of this.fieldTypes()) {
+ const name = f[0];
+ const member = this.members[name];
+ const size = member.size();
emsc.memmove(ptr, member.nativePtr, size);
ptr += size;
}
- let ba = new ByteArray(totalSize, buf, a);
+ const ba = new ByteArray(totalSize, buf, a);
return new EccSignaturePurpose(this.purpose(), ba);
}
toJson() {
- let res: any = {};
- for (let f of this.fieldTypes()) {
- let name = f[0];
- let member = this.members[name];
+ const res: any = {};
+ for (const f of this.fieldTypes()) {
+ const name = f[0];
+ const member = this.members[name];
if (!member) {
throw Error(`Member ${name} not set`);
}
res[name] = member.toJson();
}
- res["purpose"] = this.purpose();
+ res.purpose = this.purpose();
return res;
}
protected set(name: string, value: PackedArenaObject) {
- let typemap: any = {};
- for (let f of this.fieldTypes()) {
+ const typemap: any = {};
+ for (const f of this.fieldTypes()) {
typemap[f[0]] = f[1];
}
if (!(name in typemap)) {
@@ -969,7 +881,7 @@ export class WithdrawRequestPS extends SignatureStruct {
["amount_with_fee", AmountNbo],
["withdraw_fee", AmountNbo],
["h_denomination_pub", HashCode],
- ["h_coin_envelope", HashCode]
+ ["h_coin_envelope", HashCode],
];
}
}
@@ -1023,7 +935,7 @@ export class RefreshMeltCoinAffirmationPS extends SignatureStruct {
["session_hash", HashCode],
["amount_with_fee", AmountNbo],
["melt_fee", AmountNbo],
- ["coin_pub", EddsaPublicKey]
+ ["coin_pub", EddsaPublicKey],
];
}
}
@@ -1060,21 +972,21 @@ export class MasterWireFeePS extends SignatureStruct {
export class AbsoluteTimeNbo extends PackedArenaObject {
static fromTalerString(s: string): AbsoluteTimeNbo {
- let x = new AbsoluteTimeNbo();
+ const x = new AbsoluteTimeNbo();
x.alloc();
- let r = /Date\(([0-9]+)\)/;
- let m = r.exec(s);
- if (!m || m.length != 2) {
+ const r = /Date\(([0-9]+)\)/;
+ const m = r.exec(s);
+ if (!m || m.length !== 2) {
throw Error();
}
- let n = parseInt(m[1]) * 1000000;
+ const n = parseInt(m[1], 10) * 1000000;
// XXX: This only works up to 54 bit numbers.
set64(x.nativePtr, n);
return x;
}
static fromStampSeconds(stamp: number): AbsoluteTimeNbo {
- let x = new AbsoluteTimeNbo();
+ const x = new AbsoluteTimeNbo();
x.alloc();
// XXX: This only works up to 54 bit numbers.
set64(x.nativePtr, stamp * 1000000);
@@ -1107,7 +1019,7 @@ function set32(p: number, n: number) {
export class UInt64 extends PackedArenaObject {
static fromNumber(n: number): UInt64 {
- let x = new UInt64();
+ const x = new UInt64();
x.alloc();
set64(x.nativePtr, n);
return x;
@@ -1121,7 +1033,7 @@ export class UInt64 extends PackedArenaObject {
export class UInt32 extends PackedArenaObject {
static fromNumber(n: number): UInt64 {
- let x = new UInt32();
+ const x = new UInt32();
x.alloc();
set32(x.nativePtr, n);
return x;
@@ -1204,7 +1116,7 @@ export class DenominationKeyValidityPS extends SignatureStruct {
["fee_deposit", AmountNbo],
["fee_refresh", AmountNbo],
["fee_refund", AmountNbo],
- ["denom_hash", HashCode]
+ ["denom_hash", HashCode],
];
}
}
@@ -1283,18 +1195,18 @@ export function rsaBlind(hashCode: HashCode,
blindingKey: RsaBlindingKeySecret,
pkey: RsaPublicKey,
arena?: Arena): ByteArray|null {
- let buf_ptr_out = emscAlloc.malloc(PTR_SIZE);
- let buf_size_out = emscAlloc.malloc(PTR_SIZE);
- let res = emscAlloc.rsa_blind(hashCode.nativePtr,
+ const buf_ptr_out = emscAlloc.malloc(PTR_SIZE);
+ const buf_size_out = emscAlloc.malloc(PTR_SIZE);
+ const res = emscAlloc.rsa_blind(hashCode.nativePtr,
blindingKey.nativePtr,
pkey.nativePtr,
buf_ptr_out,
buf_size_out);
- let buf_ptr = emscLib.getValue(buf_ptr_out, '*');
- let buf_size = emscLib.getValue(buf_size_out, '*');
+ const buf_ptr = emscLib.getValue(buf_ptr_out, "*");
+ const buf_size = emscLib.getValue(buf_size_out, "*");
emsc.free(buf_ptr_out);
emsc.free(buf_size_out);
- if (res != GNUNET_OK) {
+ if (res !== GNUNET_OK) {
// malicious key
return null;
}
@@ -1308,9 +1220,9 @@ export function rsaBlind(hashCode: HashCode,
export function eddsaSign(purpose: EccSignaturePurpose,
priv: EddsaPrivateKey,
a?: Arena): EddsaSignature {
- let sig = new EddsaSignature(a);
+ const sig = new EddsaSignature(a);
sig.alloc();
- let res = emsc.eddsa_sign(priv.nativePtr, purpose.nativePtr, sig.nativePtr);
+ const res = emsc.eddsa_sign(priv.nativePtr, purpose.nativePtr, sig.nativePtr);
if (res < 1) {
throw Error("EdDSA signing failed");
}
@@ -1326,7 +1238,7 @@ export function eddsaVerify(purposeNum: number,
sig: EddsaSignature,
pub: EddsaPublicKey,
a?: Arena): boolean {
- let r = emsc.eddsa_verify(purposeNum,
+ const r = emsc.eddsa_verify(purposeNum,
verify.nativePtr,
sig.nativePtr,
pub.nativePtr);
@@ -1341,7 +1253,7 @@ export function rsaUnblind(sig: RsaSignature,
bk: RsaBlindingKeySecret,
pk: RsaPublicKey,
a?: Arena): RsaSignature {
- let x = new RsaSignature(a);
+ const x = new RsaSignature(a);
x.nativePtr = emscAlloc.rsa_unblind(sig.nativePtr,
bk.nativePtr,
pk.nativePtr);
@@ -1362,10 +1274,10 @@ export interface FreshCoin {
*/
export function ecdhEddsa(priv: EcdhePrivateKey,
pub: EddsaPublicKey): HashCode {
- let h = new HashCode();
+ const h = new HashCode();
h.alloc();
- let res = emsc.ecdh_eddsa(priv.nativePtr, pub.nativePtr, h.nativePtr);
- if (res != GNUNET_OK) {
+ const res = emsc.ecdh_eddsa(priv.nativePtr, pub.nativePtr, h.nativePtr);
+ if (res !== GNUNET_OK) {
throw Error("ecdh_eddsa failed");
}
return h;
@@ -1377,11 +1289,11 @@ export function ecdhEddsa(priv: EcdhePrivateKey,
*/
export function setupFreshCoin(secretSeed: TransferSecretP,
coinIndex: number): FreshCoin {
- let priv = new EddsaPrivateKey();
+ const priv = new EddsaPrivateKey();
priv.isWeak = true;
- let blindingKey = new RsaBlindingKeySecret();
+ const blindingKey = new RsaBlindingKeySecret();
blindingKey.isWeak = true;
- let buf = new ByteArray(priv.size() + blindingKey.size());
+ const buf = new ByteArray(priv.size() + blindingKey.size());
emsc.setup_fresh_coin(secretSeed.nativePtr, coinIndex, buf.nativePtr);
diff --git a/src/crypto/emscLoader.d.ts b/src/crypto/emscLoader.d.ts
index e46ed7f13..aac4116b5 100644
--- a/src/crypto/emscLoader.d.ts
+++ b/src/crypto/emscLoader.d.ts
@@ -20,25 +20,25 @@ declare function getLib(): EmscLib;
export interface EmscFunGen {
(name: string,
ret: string,
- args: string[]): ((...x: (number|string)[]) => any);
+ args: string[]): ((...x: Array<number|string>) => any);
(name: string,
ret: "number",
- args: string[]): ((...x: (number|string)[]) => number);
+ args: string[]): ((...x: Array<number|string>) => number);
(name: string,
ret: "void",
- args: string[]): ((...x: (number|string)[]) => void);
+ args: string[]): ((...x: Array<number|string>) => void);
(name: string,
ret: "string",
- args: string[]): ((...x: (number|string)[]) => string);
+ args: string[]): ((...x: Array<number|string>) => string);
}
interface EmscLib {
cwrap: EmscFunGen;
- ccall(name: string, ret:"number"|"string", argTypes: any[], args: any[]): any
+ ccall(name: string, ret: "number"|"string", argTypes: any[], args: any[]): any;
- stringToUTF8(s: string, addr: number, maxLength: number): void
+ stringToUTF8(s: string, addr: number, maxLength: number): void;
_free(ptr: number): void;
diff --git a/src/crypto/nodeWorker.ts b/src/crypto/nodeWorker.ts
index afa2930a8..4352b66c2 100644
--- a/src/crypto/nodeWorker.ts
+++ b/src/crypto/nodeWorker.ts
@@ -14,6 +14,9 @@
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
+
+// tslint:disable:no-var-requires
+
const path = require("path");
const fork = require("child_process").fork;
@@ -49,7 +52,7 @@ export class Worker {
}
});
- this.child.send({scriptFilename,cwd: process.cwd()});
+ this.child.send({scriptFilename, cwd: process.cwd()});
}
addEventListener(event: "message" | "error", fn: (x: any) => void): void {
diff --git a/src/crypto/nodeWorkerEntry.ts b/src/crypto/nodeWorkerEntry.ts
index aa6f57599..ff7f8766b 100644
--- a/src/crypto/nodeWorkerEntry.ts
+++ b/src/crypto/nodeWorkerEntry.ts
@@ -15,6 +15,8 @@
*/
+// tslint:disable:no-var-requires
+
const fs = require("fs");
const vm = require("vm");
@@ -22,57 +24,53 @@ process.once("message", (obj: any) => {
const g: any = global as any;
(g as any).self = {
+ addEventListener: (event: "error" | "message", fn: (x: any) => void) => {
+ if (event === "error") {
+ g.onerror = fn;
+ } else if (event === "message") {
+ g.onmessage = fn;
+ }
+ },
close: () => {
process.exit(0);
},
- postMessage: (msg: any) => {
- const str: string = JSON.stringify({data: msg});
+ onerror: (err: any) => {
+ const str: string = JSON.stringify({error: err.message, stack: err.stack});
if (process.send) {
process.send(str);
}
},
onmessage: undefined,
- onerror: (err: any) => {
- const str: string = JSON.stringify({error: err.message, stack: err.stack});
+ postMessage: (msg: any) => {
+ const str: string = JSON.stringify({data: msg});
if (process.send) {
process.send(str);
}
},
- addEventListener: (event: "error" | "message", fn: (x: any) => void) => {
- if (event == "error") {
- g.onerror = fn;
- } else if (event == "message") {
- g.onmessage = fn;
- }
- },
};
g.__dirname = obj.cwd;
g.__filename = __filename;
- //g.require = require;
- //g.module = module;
- //g.exports = module.exports;
-
g.importScripts = (...files: string[]) => {
if (files.length > 0) {
- vm.createScript(files.map(file => fs.readFileSync(file, "utf8")).join("\n")).runInThisContext();
+ vm.createScript(files.map((file) => fs.readFileSync(file, "utf8")).join("\n")).runInThisContext();
}
};
- Object.keys(g.self).forEach(key => {
+ Object.keys(g.self).forEach((key) => {
g[key] = g.self[key];
});
process.on("message", (msg: any) => {
try {
- (g.onmessage || g.self.onmessage || (() => {}))(JSON.parse(msg));
+ (g.onmessage || g.self.onmessage || (() => undefined))(JSON.parse(msg));
} catch (err) {
- (g.onerror || g.self.onerror || (() => {}))(err);
+ (g.onerror || g.self.onerror || (() => undefined))(err);
}
});
process.on("error", (err: any) => {
- (g.onerror || g.self.onerror || (() => {}))(err);
+ (g.onerror || g.self.onerror || (() => undefined))(err);
});
require(obj.scriptFilename);
diff --git a/src/helpers-test.ts b/src/helpers-test.ts
index 4e9b994d6..8ce3c8e2d 100644
--- a/src/helpers-test.ts
+++ b/src/helpers-test.ts
@@ -1,8 +1,25 @@
+/*
+ This file is part of TALER
+ (C) 2017 Inria and 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, see <http://www.gnu.org/licenses/>
+ */
+
+
import {test} from "ava";
import * as helpers from "./helpers";
-test("URL canonicalization", t => {
+test("URL canonicalization", (t) => {
// converts to relative, adds https
t.is(
"https://alice.example.com/exchange/",
diff --git a/src/helpers.ts b/src/helpers.ts
index 5e3ef06d5..e5eb40211 100644
--- a/src/helpers.ts
+++ b/src/helpers.ts
@@ -30,7 +30,7 @@ import URI = require("urijs");
* settings such as significant digits or currency symbols.
*/
export function amountToPretty(amount: AmountJson): string {
- let x = amount.value + amount.fraction / Amounts.fractionalBase;
+ const x = amount.value + amount.fraction / Amounts.fractionalBase;
return `${x} ${amount.currency}`;
}
@@ -41,14 +41,14 @@ export function amountToPretty(amount: AmountJson): string {
* See http://api.taler.net/wallet.html#general
*/
export function canonicalizeBaseUrl(url: string) {
- let x = new URI(url);
+ const x = new URI(url);
if (!x.protocol()) {
x.protocol("https");
}
x.path(x.path() + "/").normalizePath();
x.fragment("");
x.query();
- return x.href()
+ return x.href();
}
@@ -59,23 +59,23 @@ export function canonicalizeBaseUrl(url: string) {
export function canonicalJson(obj: any): string {
// Check for cycles, etc.
JSON.stringify(obj);
- if (typeof obj == "string" || typeof obj == "number" || obj === null) {
- return JSON.stringify(obj)
+ if (typeof obj === "string" || typeof obj === "number" || obj === null) {
+ return JSON.stringify(obj);
}
if (Array.isArray(obj)) {
- let objs: string[] = obj.map((e) => canonicalJson(e));
- return `[${objs.join(',')}]`;
+ const objs: string[] = obj.map((e) => canonicalJson(e));
+ return `[${objs.join(",")}]`;
}
- let keys: string[] = [];
- for (let key in obj) {
+ const keys: string[] = [];
+ for (const key in obj) {
keys.push(key);
}
keys.sort();
let s = "{";
for (let i = 0; i < keys.length; i++) {
- let key = keys[i];
+ const key = keys[i];
s += JSON.stringify(key) + ":" + canonicalJson(obj[key]);
- if (i != keys.length - 1) {
+ if (i !== keys.length - 1) {
s += ",";
}
}
@@ -92,7 +92,7 @@ export function deepEquals(x: any, y: any): boolean {
return false;
}
- var p = Object.keys(x);
+ const p = Object.keys(x);
return Object.keys(y).every((i) => p.indexOf(i) !== -1) &&
p.every((i) => deepEquals(x[i], y[i]));
}
@@ -112,7 +112,7 @@ export function getTalerStampSec(stamp: string): number | null {
if (!m) {
return null;
}
- return parseInt(m[1]);
+ return parseInt(m[1], 10);
}
@@ -121,7 +121,7 @@ export function getTalerStampSec(stamp: string): number | null {
* Returns null if input is not in the right format.
*/
export function getTalerStampDate(stamp: string): Date | null {
- let sec = getTalerStampSec(stamp);
+ const sec = getTalerStampSec(stamp);
if (sec == null) {
return null;
}
diff --git a/src/http.ts b/src/http.ts
index 965a44a97..895b10973 100644
--- a/src/http.ts
+++ b/src/http.ts
@@ -46,10 +46,10 @@ export interface HttpRequestLibrary {
*/
export class BrowserHttpLib {
private req(method: string,
- url: string,
- options?: any): Promise<HttpResponse> {
+ url: string,
+ options?: any): Promise<HttpResponse> {
return new Promise<HttpResponse>((resolve, reject) => {
- let myRequest = new XMLHttpRequest();
+ const myRequest = new XMLHttpRequest();
myRequest.open(method, url);
if (options && options.req) {
myRequest.send(options.req);
@@ -57,10 +57,10 @@ export class BrowserHttpLib {
myRequest.send();
}
myRequest.addEventListener("readystatechange", (e) => {
- if (myRequest.readyState == XMLHttpRequest.DONE) {
- let resp = {
+ if (myRequest.readyState === XMLHttpRequest.DONE) {
+ const resp = {
+ responseText: myRequest.responseText,
status: myRequest.status,
- responseText: myRequest.responseText
};
resolve(resp);
}
diff --git a/src/logging.ts b/src/logging.ts
index d5d6debf4..19dd2f76c 100644
--- a/src/logging.ts
+++ b/src/logging.ts
@@ -20,7 +20,11 @@
* @author Florian Dold
*/
-import {Store, QueryRoot, openPromise} from "./query";
+import {
+ QueryRoot,
+ Store,
+ openPromise,
+} from "./query";
export type Level = "error" | "debug" | "info" | "warn";
@@ -41,83 +45,92 @@ function makeDebug() {
}
export async function log(msg: string, level: Level = "info"): Promise<void> {
- let ci = getCallInfo(2);
+ const ci = getCallInfo(2);
return record(level, msg, undefined, ci.file, ci.line, ci.column);
}
function getCallInfo(level: number) {
// see https://github.com/v8/v8/wiki/Stack-Trace-API
- let stack = Error().stack;
+ const stack = Error().stack;
if (!stack) {
return unknownFrame;
}
- let lines = stack.split("\n");
+ const lines = stack.split("\n");
return parseStackLine(lines[level + 1]);
}
interface Frame {
- file?: string;
- method?: string;
column?: number;
+ file?: string;
line?: number;
+ method?: string;
}
const unknownFrame: Frame = {
+ column: 0,
file: "(unknown)",
- method: "(unknown)",
line: 0,
- column: 0
+ method: "(unknown)",
};
/**
* Adapted from https://github.com/errwischt/stacktrace-parser.
*/
function parseStackLine(stackLine: string): Frame {
+ // tslint:disable-next-line:max-line-length
const chrome = /^\s*at (?:(?:(?:Anonymous function)?|((?:\[object object\])?\S+(?: \[as \S+\])?)) )?\(?((?:file|http|https):.*?):(\d+)(?::(\d+))?\)?\s*$/i;
const gecko = /^(?:\s*([^@]*)(?:\((.*?)\))?@)?(\S.*?):(\d+)(?::(\d+))?\s*$/i;
const node = /^\s*at (?:((?:\[object object\])?\S+(?: \[as \S+\])?) )?\(?(.*?):(\d+)(?::(\d+))?\)?\s*$/i;
let parts;
- if ((parts = gecko.exec(stackLine))) {
- let f: Frame = {
+ parts = gecko.exec(stackLine);
+ if (parts) {
+ const f: Frame = {
+ column: parts[5] ? +parts[5] : undefined,
file: parts[3],
- method: parts[1] || "(unknown)",
line: +parts[4],
- column: parts[5] ? +parts[5] : undefined,
+ method: parts[1] || "(unknown)",
};
return f;
- } else if ((parts = chrome.exec(stackLine))) {
- let f: Frame = {
+ }
+
+ parts = chrome.exec(stackLine);
+ if (parts) {
+ const f: Frame = {
+ column: parts[4] ? +parts[4] : undefined,
file: parts[2],
- method: parts[1] || "(unknown)",
line: +parts[3],
- column: parts[4] ? +parts[4] : undefined,
+ method: parts[1] || "(unknown)",
};
return f;
- } else if ((parts = node.exec(stackLine))) {
- let f: Frame = {
+ }
+
+ parts = node.exec(stackLine);
+ if (parts) {
+ const f: Frame = {
+ column: parts[4] ? +parts[4] : undefined,
file: parts[2],
- method: parts[1] || "(unknown)",
line: +parts[3],
- column: parts[4] ? +parts[4] : undefined,
+ method: parts[1] || "(unknown)",
};
return f;
}
+
return unknownFrame;
}
-let db: IDBDatabase|undefined = undefined;
+let db: IDBDatabase|undefined;
export interface LogEntry {
- timestamp: number;
+ col?: number;
+ detail?: string;
+ id?: number;
level: string;
+ line?: number;
msg: string;
- detail?: string;
source?: string;
- col?: number;
- line?: number;
- id?: number;
+ timestamp: number;
}
export async function getLogs(): Promise<LogEntry[]> {
@@ -140,7 +153,7 @@ export async function recordException(msg: string, e: any): Promise<void> {
try {
stack = e.stack;
if (stack) {
- let lines = stack.split("\n");
+ const lines = stack.split("\n");
frame = parseStackLine(lines[1]);
}
} catch (e) {
@@ -152,7 +165,12 @@ export async function recordException(msg: string, e: any): Promise<void> {
return record("error", e.toString(), stack, frame.file, frame.line, frame.column);
}
-export async function record(level: Level, msg: string, detail?: string, source?: string, line?: number, col?: number): Promise<void> {
+export async function record(level: Level,
+ msg: string,
+ detail?: string,
+ source?: string,
+ line?: number,
+ col?: number): Promise<void> {
if (typeof indexedDB === "undefined") {
return;
}
@@ -160,7 +178,7 @@ export async function record(level: Level, msg: string, detail?: string, source?
let myBarrier: any;
if (barrier) {
- let p = barrier.promise;
+ const p = barrier.promise;
myBarrier = barrier = openPromise();
await p;
} else {
@@ -172,20 +190,20 @@ export async function record(level: Level, msg: string, detail?: string, source?
db = await openLoggingDb();
}
- let count = await new QueryRoot(db).count(logsStore);
+ const count = await new QueryRoot(db).count(logsStore);
if (count > 1000) {
await new QueryRoot(db).deleteIf(logsStore, (e, i) => (i < 200));
}
- let entry: LogEntry = {
- timestamp: new Date().getTime(),
+ const entry: LogEntry = {
+ col,
+ detail,
level,
+ line,
msg,
source,
- line,
- col,
- detail,
+ timestamp: new Date().getTime(),
};
await new QueryRoot(db).put(logsStore, entry);
} finally {
@@ -207,15 +225,15 @@ export function openLoggingDb(): Promise<IDBDatabase> {
resolve(req.result);
};
req.onupgradeneeded = (e) => {
- const db = req.result;
- if (e.oldVersion != 0) {
+ const resDb = req.result;
+ if (e.oldVersion !== 0) {
try {
- db.deleteObjectStore("logs");
+ resDb.deleteObjectStore("logs");
} catch (e) {
console.error(e);
}
}
- db.createObjectStore("logs", {keyPath: "id", autoIncrement: true});
+ resDb.createObjectStore("logs", {keyPath: "id", autoIncrement: true});
};
});
}
diff --git a/src/pages/show-db.ts b/src/pages/show-db.ts
index 955253680..d95951385 100644
--- a/src/pages/show-db.ts
+++ b/src/pages/show-db.ts
@@ -23,32 +23,32 @@
function replacer(match: string, pIndent: string, pKey: string, pVal: string,
pEnd: string) {
- var key = '<span class=json-key>';
- var val = '<span class=json-value>';
- var str = '<span class=json-string>';
- var r = pIndent || '';
+ const key = "<span class=json-key>";
+ const val = "<span class=json-value>";
+ const str = "<span class=json-string>";
+ let r = pIndent || "";
if (pKey) {
- r = r + key + '"' + pKey.replace(/[": ]/g, '') + '":</span> ';
+ r = r + key + '"' + pKey.replace(/[": ]/g, "") + '":</span> ';
}
if (pVal) {
- r = r + (pVal[0] == '"' ? str : val) + pVal + '</span>';
+ r = r + (pVal[0] === '"' ? str : val) + pVal + "</span>";
}
- return r + (pEnd || '');
+ return r + (pEnd || "");
}
function prettyPrint(obj: any) {
- var jsonLine = /^( *)("[\w]+": )?("[^"]*"|[\w.+-]*)?([,[{])?$/mg;
+ const jsonLine = /^( *)("[\w]+": )?("[^"]*"|[\w.+-]*)?([,[{])?$/mg;
return JSON.stringify(obj, null as any, 3)
- .replace(/&/g, '&amp;').replace(/\\"/g, '&quot;')
- .replace(/</g, '&lt;').replace(/>/g, '&gt;')
+ .replace(/&/g, "&amp;").replace(/\\"/g, "&quot;")
+ .replace(/</g, "&lt;").replace(/>/g, "&gt;")
.replace(jsonLine, replacer);
}
document.addEventListener("DOMContentLoaded", () => {
- chrome.runtime.sendMessage({type: 'dump-db'}, (resp) => {
- const el = document.getElementById('dump');
+ chrome.runtime.sendMessage({type: "dump-db"}, (resp) => {
+ const el = document.getElementById("dump");
if (!el) {
throw Error();
}
@@ -56,7 +56,7 @@ document.addEventListener("DOMContentLoaded", () => {
document.getElementById("download")!.addEventListener("click", (evt) => {
console.log("creating download");
- let element = document.createElement("a");
+ const element = document.createElement("a");
element.setAttribute("href", "data:text/plain;charset=utf-8," + encodeURIComponent(JSON.stringify(resp)));
element.setAttribute("download", "wallet-dump.txt");
element.style.display = "none";
@@ -67,9 +67,9 @@ document.addEventListener("DOMContentLoaded", () => {
});
- let fileInput = document.getElementById("fileInput")! as HTMLInputElement;
+ const fileInput = document.getElementById("fileInput")! as HTMLInputElement;
fileInput.onchange = (evt) => {
- if (!fileInput.files || fileInput.files.length != 1) {
+ if (!fileInput.files || fileInput.files.length !== 1) {
alert("please select exactly one file to import");
return;
}
@@ -77,9 +77,9 @@ document.addEventListener("DOMContentLoaded", () => {
const fr = new FileReader();
fr.onload = (e: any) => {
console.log("got file");
- let dump = JSON.parse(e.target.result);
+ const dump = JSON.parse(e.target.result);
console.log("parsed contents", dump);
- chrome.runtime.sendMessage({ type: 'import-db', detail: { dump } }, (resp) => {
+ chrome.runtime.sendMessage({ type: "import-db", detail: { dump } }, (resp) => {
alert("loaded");
});
};
diff --git a/src/query.ts b/src/query.ts
index c593f061e..78b810371 100644
--- a/src/query.ts
+++ b/src/query.ts
@@ -21,42 +21,42 @@
* @author Florian Dold
*/
-"use strict";
-
-export interface JoinResult<L,R> {
+/**
+ * Result of an inner join.
+ */
+export interface JoinResult<L, R> {
left: L;
right: R;
}
-export interface JoinLeftResult<L,R> {
+/**
+ * Result of a left outer join.
+ */
+export interface JoinLeftResult<L, R> {
left: L;
right?: R;
}
+/**
+ * Definition of an object store.
+ */
export class Store<T> {
- name: string;
- validator?: (v: T) => T;
- storeParams?: IDBObjectStoreParameters;
-
- constructor(name: string, storeParams?: IDBObjectStoreParameters,
- validator?: (v: T) => T) {
- this.name = name;
- this.validator = validator;
- this.storeParams = storeParams;
+ constructor(public name: string,
+ public storeParams?: IDBObjectStoreParameters,
+ public validator?: (v: T) => T) {
}
}
-export class Index<S extends IDBValidKey,T> {
- indexName: string;
+/**
+ * Definition of an index.
+ */
+export class Index<S extends IDBValidKey, T> {
storeName: string;
- keyPath: string | string[];
- constructor(s: Store<T>, indexName: string, keyPath: string | string[]) {
+ constructor(s: Store<T>, public indexName: string, public keyPath: string | string[]) {
this.storeName = s.name;
- this.indexName = indexName;
- this.keyPath = keyPath;
}
}
@@ -65,17 +65,58 @@ export class Index<S extends IDBValidKey,T> {
* with indices.
*/
export interface QueryStream<T> {
- indexJoin<S,I extends IDBValidKey>(index: Index<I,S>,
- keyFn: (obj: T) => I): QueryStream<JoinResult<T, S>>;
- indexJoinLeft<S,I extends IDBValidKey>(index: Index<I,S>,
- keyFn: (obj: T) => I): QueryStream<JoinLeftResult<T, S>>;
- keyJoin<S,I extends IDBValidKey>(store: Store<S>,
- keyFn: (obj: T) => I): QueryStream<JoinResult<T,S>>;
- filter(f: (T: any) => boolean): QueryStream<T>;
+ /**
+ * Join the current query with values from an index.
+ * The left side of the join is extracted via a function from the stream's
+ * result, the right side of the join is the key of the index.
+ */
+ indexJoin<S, I extends IDBValidKey>(index: Index<I, S>, keyFn: (obj: T) => I): QueryStream<JoinResult<T, S>>;
+ /**
+ * Join the current query with values from an index, and keep values in the
+ * current stream that don't have a match. The left side of the join is
+ * extracted via a function from the stream's result, the right side of the
+ * join is the key of the index.
+ */
+ indexJoinLeft<S, I extends IDBValidKey>(index: Index<I, S>,
+ keyFn: (obj: T) => I): QueryStream<JoinLeftResult<T, S>>;
+ /**
+ * Join the current query with values from another object store.
+ * The left side of the join is extracted via a function over the current query,
+ * the right side of the join is the key of the object store.
+ */
+ keyJoin<S, I extends IDBValidKey>(store: Store<S>, keyFn: (obj: T) => I): QueryStream<JoinResult<T, S>>;
+
+ /**
+ * Only keep elements in the result stream for which the predicate returns
+ * true.
+ */
+ filter(f: (x: T) => boolean): QueryStream<T>;
+
+ /**
+ * Reduce the stream, resulting in a single value.
+ */
reduce<S>(f: (v: T, acc: S) => S, start?: S): Promise<S>;
- map<S>(f: (x:T) => S): QueryStream<S>;
+
+ /**
+ * Map each element of the stream using a function, resulting in another
+ * stream of a different type.
+ */
+ map<S>(f: (x: T) => S): QueryStream<S>;
+
+ /**
+ * Map each element of the stream to a potentially empty array, and collect
+ * the result in a stream of the flattened arrays.
+ */
flatMap<S>(f: (x: T) => S[]): QueryStream<S>;
+
+ /**
+ * Collect the stream into an array and return a promise for it.
+ */
toArray(): Promise<T[]>;
+
+ /**
+ * Get the first value of the stream.
+ */
first(): QueryValue<T>;
then(onfulfill: any, onreject: any): any;
@@ -99,7 +140,7 @@ abstract class BaseQueryValue<T> implements QueryValue<T> {
}
map<S>(f: (x: T) => S): QueryValue<S> {
- return new MapQueryValue<T,S>(this, f);
+ return new MapQueryValue<T, S>(this, f);
}
cond<R>(f: (x: T) => boolean, onTrue: (r: QueryRoot) => R, onFalse: (r: QueryRoot) => R): Promise<void> {
@@ -141,7 +182,7 @@ class FirstQueryValue<T> extends BaseQueryValue<T> {
}
}
-class MapQueryValue<T,S> extends BaseQueryValue<S> {
+class MapQueryValue<T, S> extends BaseQueryValue<S> {
mapFn: (x: T) => S;
v: BaseQueryValue<T>;
@@ -157,7 +198,10 @@ class MapQueryValue<T,S> extends BaseQueryValue<S> {
}
-export let AbortTransaction = Symbol("abort_transaction");
+/**
+ * Exception that should be thrown by client code to abort a transaction.
+ */
+export const AbortTransaction = Symbol("abort_transaction");
/**
* Get an unresolved promise together with its extracted resolve / reject
@@ -193,26 +237,27 @@ abstract class QueryStreamBase<T> implements QueryStream<T>, PromiseLike<void> {
return new FirstQueryValue(this);
}
- then<R>(onfulfilled: (value: void) => R | PromiseLike<R>, onrejected: (reason: any) => R | PromiseLike<R>): PromiseLike<R> {
+ then<R>(onfulfilled: (value: void) => R | PromiseLike<R>,
+ onrejected: (reason: any) => R | PromiseLike<R>): PromiseLike<R> {
return this.root.then(onfulfilled, onrejected);
}
flatMap<S>(f: (x: T) => S[]): QueryStream<S> {
- return new QueryStreamFlatMap<T,S>(this, f);
+ return new QueryStreamFlatMap<T, S>(this, f);
}
map<S>(f: (x: T) => S): QueryStream<S> {
return new QueryStreamMap(this, f);
}
- indexJoin<S,I extends IDBValidKey>(index: Index<I,S>,
- keyFn: (obj: T) => I): QueryStream<JoinResult<T, S>> {
+ indexJoin<S, I extends IDBValidKey>(index: Index<I, S>,
+ keyFn: (obj: T) => I): QueryStream<JoinResult<T, S>> {
this.root.addStoreAccess(index.storeName, false);
return new QueryStreamIndexJoin<T, S>(this, index.storeName, index.indexName, keyFn);
}
- indexJoinLeft<S,I extends IDBValidKey>(index: Index<I,S>,
- keyFn: (obj: T) => I): QueryStream<JoinLeftResult<T, S>> {
+ indexJoinLeft<S, I extends IDBValidKey>(index: Index<I, S>,
+ keyFn: (obj: T) => I): QueryStream<JoinLeftResult<T, S>> {
this.root.addStoreAccess(index.storeName, false);
return new QueryStreamIndexJoinLeft<T, S>(this, index.storeName, index.indexName, keyFn);
}
@@ -228,8 +273,8 @@ abstract class QueryStreamBase<T> implements QueryStream<T>, PromiseLike<void> {
}
toArray(): Promise<T[]> {
- let {resolve, promise} = openPromise();
- let values: T[] = [];
+ const {resolve, promise} = openPromise();
+ const values: T[] = [];
this.subscribe((isDone, value) => {
if (isDone) {
@@ -245,7 +290,7 @@ abstract class QueryStreamBase<T> implements QueryStream<T>, PromiseLike<void> {
}
reduce<A>(f: (x: any, acc?: A) => A, init?: A): Promise<any> {
- let {resolve, promise} = openPromise();
+ const {resolve, promise} = openPromise();
let acc = init;
this.subscribe((isDone, value) => {
@@ -265,10 +310,7 @@ abstract class QueryStreamBase<T> implements QueryStream<T>, PromiseLike<void> {
type FilterFn = (e: any) => boolean;
type SubscribeFn = (done: boolean, value: any, tx: IDBTransaction) => void;
type SubscribeOneFn = (value: any, tx: IDBTransaction) => void;
-
-interface FlatMapFn<T> {
- (v: T): T[];
-}
+type FlatMapFn<T> = (v: T) => T[];
class QueryStreamFilter<T> extends QueryStreamBase<T> {
s: QueryStreamBase<T>;
@@ -294,7 +336,7 @@ class QueryStreamFilter<T> extends QueryStreamBase<T> {
}
-class QueryStreamFlatMap<T,S> extends QueryStreamBase<S> {
+class QueryStreamFlatMap<T, S> extends QueryStreamBase<S> {
s: QueryStreamBase<T>;
flatMapFn: (v: T) => S[];
@@ -310,16 +352,16 @@ class QueryStreamFlatMap<T,S> extends QueryStreamBase<S> {
f(true, undefined, tx);
return;
}
- let values = this.flatMapFn(value);
- for (let v in values) {
- f(false, value, tx)
+ const values = this.flatMapFn(value);
+ for (const v in values) {
+ f(false, value, tx);
}
});
}
}
-class QueryStreamMap<S,T> extends QueryStreamBase<T> {
+class QueryStreamMap<S, T> extends QueryStreamBase<T> {
s: QueryStreamBase<S>;
mapFn: (v: S) => T;
@@ -335,7 +377,7 @@ class QueryStreamMap<S,T> extends QueryStreamBase<T> {
f(true, undefined, tx);
return;
}
- let mappedValue = this.mapFn(value);
+ const mappedValue = this.mapFn(value);
f(false, mappedValue, tx);
});
}
@@ -363,15 +405,15 @@ class QueryStreamIndexJoin<T, S> extends QueryStreamBase<JoinResult<T, S>> {
f(true, undefined, tx);
return;
}
- let s = tx.objectStore(this.storeName).index(this.indexName);
- let req = s.openCursor(IDBKeyRange.only(this.key(value)));
+ const s = tx.objectStore(this.storeName).index(this.indexName);
+ const req = s.openCursor(IDBKeyRange.only(this.key(value)));
req.onsuccess = () => {
- let cursor = req.result;
+ const cursor = req.result;
if (cursor) {
f(false, {left: value, right: cursor.value}, tx);
cursor.continue();
}
- }
+ };
});
}
}
@@ -402,7 +444,7 @@ class QueryStreamIndexJoinLeft<T, S> extends QueryStreamBase<JoinLeftResult<T, S
const req = s.openCursor(IDBKeyRange.only(this.key(value)));
let gotMatch = false;
req.onsuccess = () => {
- let cursor = req.result;
+ const cursor = req.result;
if (cursor) {
gotMatch = true;
f(false, {left: value, right: cursor.value}, tx);
@@ -412,7 +454,7 @@ class QueryStreamIndexJoinLeft<T, S> extends QueryStreamBase<JoinLeftResult<T, S
f(false, {left: value}, tx);
}
}
- }
+ };
});
}
}
@@ -437,17 +479,17 @@ class QueryStreamKeyJoin<T, S> extends QueryStreamBase<JoinResult<T, S>> {
f(true, undefined, tx);
return;
}
- let s = tx.objectStore(this.storeName);
- let req = s.openCursor(IDBKeyRange.only(this.key(value)));
+ const s = tx.objectStore(this.storeName);
+ const req = s.openCursor(IDBKeyRange.only(this.key(value)));
req.onsuccess = () => {
- let cursor = req.result;
+ const cursor = req.result;
if (cursor) {
- f(false, {left:value, right: cursor.value}, tx);
+ f(false, {left: value, right: cursor.value}, tx);
cursor.continue();
} else {
f(true, undefined, tx);
}
- }
+ };
});
}
}
@@ -464,7 +506,7 @@ class IterQueryStream<T> extends QueryStreamBase<T> {
this.storeName = storeName;
this.subscribers = [];
- let doIt = (tx: IDBTransaction) => {
+ const doIt = (tx: IDBTransaction) => {
const {indexName = void 0, only = void 0} = this.options;
let s: any;
if (indexName !== void 0) {
@@ -473,24 +515,24 @@ class IterQueryStream<T> extends QueryStreamBase<T> {
} else {
s = tx.objectStore(this.storeName);
}
- let kr: IDBKeyRange | undefined = undefined;
+ let kr: IDBKeyRange | undefined;
if (only !== undefined) {
kr = IDBKeyRange.only(this.options.only);
}
- let req = s.openCursor(kr);
+ const req = s.openCursor(kr);
req.onsuccess = () => {
- let cursor: IDBCursorWithValue = req.result;
+ const cursor: IDBCursorWithValue = req.result;
if (cursor) {
- for (let f of this.subscribers) {
+ for (const f of this.subscribers) {
f(false, cursor.value, tx);
}
cursor.continue();
} else {
- for (let f of this.subscribers) {
+ for (const f of this.subscribers) {
f(true, undefined, tx);
}
}
- }
+ };
};
this.root.addWork(doIt);
@@ -503,8 +545,7 @@ class IterQueryStream<T> extends QueryStreamBase<T> {
export class QueryRoot implements PromiseLike<void> {
- private work: ((t: IDBTransaction) => void)[] = [];
- db: IDBDatabase;
+ private work: Array<((t: IDBTransaction) => void)> = [];
private stores = new Set();
private kickoffPromise: Promise<void>;
@@ -518,20 +559,23 @@ export class QueryRoot implements PromiseLike<void> {
private finished: boolean = false;
- constructor(db: IDBDatabase) {
- this.db = db;
+ constructor(public db: IDBDatabase) {
}
- then<R>(onfulfilled: (value: void) => R | PromiseLike<R>, onrejected: (reason: any) => R | PromiseLike<R>): PromiseLike<R> {
+ then<R>(onfulfilled: (value: void) => R | PromiseLike<R>,
+ onrejected: (reason: any) => R | PromiseLike<R>): PromiseLike<R> {
return this.finish().then(onfulfilled, onrejected);
}
- checkFinished() {
+ private checkFinished() {
if (this.finished) {
throw Error("Can't add work to query after it was started");
}
}
+ /**
+ * Get a stream of all objects in the store.
+ */
iter<T>(store: Store<T>): QueryStream<T> {
this.checkFinished();
this.stores.add(store.name);
@@ -539,6 +583,9 @@ export class QueryRoot implements PromiseLike<void> {
return new IterQueryStream<T>(this, store.name, {});
}
+ /**
+ * Count the number of objects in a store.
+ */
count<T>(store: Store<T>): Promise<number> {
this.checkFinished();
const {resolve, promise} = openPromise();
@@ -549,7 +596,7 @@ export class QueryRoot implements PromiseLike<void> {
req.onsuccess = () => {
resolve(req.result);
};
- }
+ };
this.addWork(doCount, store.name, false);
return Promise.resolve()
@@ -558,6 +605,9 @@ export class QueryRoot implements PromiseLike<void> {
}
+ /**
+ * Delete all objects in a store that match a predicate.
+ */
deleteIf<T>(store: Store<T>, predicate: (x: T, n: number) => boolean): QueryRoot {
this.checkFinished();
const doDeleteIf = (tx: IDBTransaction) => {
@@ -565,27 +615,27 @@ export class QueryRoot implements PromiseLike<void> {
const req = s.openCursor();
let n = 0;
req.onsuccess = () => {
- let cursor: IDBCursorWithValue = req.result;
+ const cursor: IDBCursorWithValue = req.result;
if (cursor) {
if (predicate(cursor.value, n++)) {
cursor.delete();
}
cursor.continue();
- }
- }
+ }
+ };
};
this.addWork(doDeleteIf, store.name, true);
return this;
}
- iterIndex<S extends IDBValidKey,T>(index: Index<S,T>,
- only?: S): QueryStream<T> {
+ iterIndex<S extends IDBValidKey, T>(index: Index<S, T>,
+ only?: S): QueryStream<T> {
this.checkFinished();
this.stores.add(index.storeName);
this.scheduleFinish();
return new IterQueryStream<T>(this, index.storeName, {
+ indexName: index.indexName,
only,
- indexName: index.indexName
});
}
@@ -596,7 +646,7 @@ export class QueryRoot implements PromiseLike<void> {
*/
put<T>(store: Store<T>, val: T): QueryRoot {
this.checkFinished();
- let doPut = (tx: IDBTransaction) => {
+ const doPut = (tx: IDBTransaction) => {
tx.objectStore(store.name).put(val);
};
this.scheduleFinish();
@@ -608,11 +658,11 @@ export class QueryRoot implements PromiseLike<void> {
putWithResult<T>(store: Store<T>, val: T): Promise<IDBValidKey> {
this.checkFinished();
const {resolve, promise} = openPromise();
- let doPutWithResult = (tx: IDBTransaction) => {
- let req = tx.objectStore(store.name).put(val);
+ const doPutWithResult = (tx: IDBTransaction) => {
+ const req = tx.objectStore(store.name).put(val);
req.onsuccess = () => {
resolve(req.result);
- }
+ };
this.scheduleFinish();
};
this.addWork(doPutWithResult, store.name, true);
@@ -622,17 +672,20 @@ export class QueryRoot implements PromiseLike<void> {
}
+ /**
+ * Get, modify and store an element inside a transaction.
+ */
mutate<T>(store: Store<T>, key: any, f: (v: T) => T): QueryRoot {
this.checkFinished();
- let doPut = (tx: IDBTransaction) => {
- let reqGet = tx.objectStore(store.name).get(key);
+ const doPut = (tx: IDBTransaction) => {
+ const reqGet = tx.objectStore(store.name).get(key);
reqGet.onsuccess = () => {
- let r = reqGet.result;
+ const r = reqGet.result;
let m: T;
try {
m = f(r);
} catch (e) {
- if (e == AbortTransaction) {
+ if (e === AbortTransaction) {
tx.abort();
return;
}
@@ -640,7 +693,7 @@ export class QueryRoot implements PromiseLike<void> {
}
tx.objectStore(store.name).put(m);
- }
+ };
};
this.scheduleFinish();
this.addWork(doPut, store.name, true);
@@ -656,7 +709,7 @@ export class QueryRoot implements PromiseLike<void> {
putAll<T>(store: Store<T>, iterable: T[]): QueryRoot {
this.checkFinished();
const doPutAll = (tx: IDBTransaction) => {
- for (let obj of iterable) {
+ for (const obj of iterable) {
tx.objectStore(store.name).put(obj);
}
};
@@ -707,8 +760,8 @@ export class QueryRoot implements PromiseLike<void> {
/**
* Get one object from a store by its key.
*/
- getIndexed<I extends IDBValidKey,T>(index: Index<I,T>,
- key: I): Promise<T|undefined> {
+ getIndexed<I extends IDBValidKey, T>(index: Index<I, T>,
+ key: I): Promise<T|undefined> {
this.checkFinished();
if (key === void 0) {
throw Error("key must not be undefined");
@@ -748,7 +801,7 @@ export class QueryRoot implements PromiseLike<void> {
this.kickoffPromise = new Promise<void>((resolve, reject) => {
// At this point, we can't add any more work
this.finished = true;
- if (this.work.length == 0) {
+ if (this.work.length === 0) {
resolve();
return;
}
@@ -760,7 +813,7 @@ export class QueryRoot implements PromiseLike<void> {
tx.onabort = () => {
reject(Error("transaction aborted"));
};
- for (let w of this.work) {
+ for (const w of this.work) {
w(tx);
}
});
diff --git a/src/timer.ts b/src/timer.ts
index 105fc8c7a..2fc2ade04 100644
--- a/src/timer.ts
+++ b/src/timer.ts
@@ -54,7 +54,7 @@ export let performanceNow = (() => {
return () => {
const t = process.hrtime();
return t[0] * 1e9 + t[1];
- }
+ };
} else if (typeof "performance" !== "undefined") {
return () => performance.now();
} else {
diff --git a/src/types-test.ts b/src/types-test.ts
index 88f9f2723..a84bdaec8 100644
--- a/src/types-test.ts
+++ b/src/types-test.ts
@@ -1,35 +1,51 @@
+/*
+ This file is part of TALER
+ (C) 2017 Inria and 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, see <http://www.gnu.org/licenses/>
+ */
+
import {test} from "ava";
import {Amounts} from "./types";
import * as types from "./types";
-let amt = (value: number, fraction: number, currency: string): types.AmountJson => ({value, fraction, currency});
+const amt = (value: number, fraction: number, currency: string): types.AmountJson => ({value, fraction, currency});
-test("amount addition (simple)", t => {
- let a1 = amt(1,0,"EUR");
- let a2 = amt(1,0,"EUR");
- let a3 = amt(2,0,"EUR");
- t.true(0 == types.Amounts.cmp(Amounts.add(a1, a2).amount, a3));
+test("amount addition (simple)", (t) => {
+ const a1 = amt(1, 0, "EUR");
+ const a2 = amt(1, 0, "EUR");
+ const a3 = amt(2, 0, "EUR");
+ t.true(0 === types.Amounts.cmp(Amounts.add(a1, a2).amount, a3));
t.pass();
});
-test("amount addition (saturation)", t => {
- let a1 = amt(1,0,"EUR");
- let res = Amounts.add(Amounts.getMaxAmount("EUR"), a1);
+test("amount addition (saturation)", (t) => {
+ const a1 = amt(1, 0, "EUR");
+ const res = Amounts.add(Amounts.getMaxAmount("EUR"), a1);
t.true(res.saturated);
t.pass();
});
-test("amount subtraction (simple)", t => {
- let a1 = amt(2,5,"EUR");
- let a2 = amt(1,0,"EUR");
- let a3 = amt(1,5,"EUR");
- t.true(0 == types.Amounts.cmp(Amounts.sub(a1, a2).amount, a3));
+test("amount subtraction (simple)", (t) => {
+ const a1 = amt(2, 5, "EUR");
+ const a2 = amt(1, 0, "EUR");
+ const a3 = amt(1, 5, "EUR");
+ t.true(0 === types.Amounts.cmp(Amounts.sub(a1, a2).amount, a3));
t.pass();
});
-test("amount subtraction (saturation)", t => {
- let a1 = amt(0,0,"EUR");
- let a2 = amt(1,0,"EUR");
+test("amount subtraction (saturation)", (t) => {
+ const a1 = amt(0, 0, "EUR");
+ const a2 = amt(1, 0, "EUR");
let res = Amounts.sub(a1, a2);
t.true(res.saturated);
res = Amounts.sub(a1, a1);
@@ -38,29 +54,29 @@ test("amount subtraction (saturation)", t => {
});
-test("contract validation", t => {
- let c = {
+test("contract validation", (t) => {
+ const c = {
H_wire: "123",
- summary: "hello",
- amount: amt(1,2,"EUR"),
+ amount: amt(1, 2, "EUR"),
auditors: [],
- pay_deadline: "Date(12346)",
- max_fee: amt(1,2,"EUR"),
- merchant_pub: "12345",
exchanges: [{master_pub: "foo", url: "foo"}],
+ fulfillment_url: "foo",
+ max_fee: amt(1, 2, "EUR"),
+ merchant_pub: "12345",
+ order_id: "test_order",
+ pay_deadline: "Date(12346)",
+ pay_url: "https://example.com/pay",
products: [],
refund_deadline: "Date(12345)",
+ summary: "hello",
timestamp: "Date(12345)",
- fulfillment_url: "foo",
wire_method: "test",
- order_id: "test_order",
- pay_url: "https://example.com/pay",
};
types.Contract.checked(c);
- let c1 = JSON.parse(JSON.stringify(c));
- c1.exchanges = []
+ const c1 = JSON.parse(JSON.stringify(c));
+ c1.exchanges = [];
try {
types.Contract.checked(c1);
@@ -70,5 +86,4 @@ test("contract validation", t => {
}
t.fail();
-
});
diff --git a/src/types.ts b/src/types.ts
index 53f98948e..91a61bc4b 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -51,20 +51,20 @@ export interface SignedAmountJson {
export interface ReserveRecord {
reserve_pub: string;
- reserve_priv: string,
- exchange_base_url: string,
- created: number,
- last_query: number | null,
+ reserve_priv: string;
+ exchange_base_url: string;
+ created: number;
+ last_query: number | null;
/**
* Current amount left in the reserve
*/
- current_amount: AmountJson | null,
+ current_amount: AmountJson | null;
/**
* Amount requested when the reserve was created.
* When a reserve is re-used (rare!) the current_amount can
* be higher than the requested_amount
*/
- requested_amount: AmountJson,
+ requested_amount: AmountJson;
/**
@@ -360,7 +360,7 @@ export interface RefreshSessionRecord {
* How much of the coin's value is melted away
* with this refresh session?
*/
- valueWithFee: AmountJson
+ valueWithFee: AmountJson;
/**
* Sum of the value of denominations we want
@@ -468,7 +468,7 @@ export interface CoinRecord {
* Reserve public key for the reserve we got this coin from,
* or zero when we got the coin from refresh.
*/
- reservePub: string|undefined,
+ reservePub: string|undefined;
/**
* Status of the coin.
@@ -528,7 +528,7 @@ interface Merchant {
export class Contract {
validate() {
- if (this.exchanges.length == 0) {
+ if (this.exchanges.length === 0) {
throw Error("no exchanges in contract");
}
}
@@ -629,27 +629,27 @@ export namespace Amounts {
export function getMaxAmount(currency: string): AmountJson {
return {
currency,
- value: Number.MAX_SAFE_INTEGER,
fraction: 2 ** 32,
- }
+ value: Number.MAX_SAFE_INTEGER,
+ };
}
export function getZero(currency: string): AmountJson {
return {
currency,
- value: 0,
fraction: 0,
- }
+ value: 0,
+ };
}
export function add(first: AmountJson, ...rest: AmountJson[]): Result {
- let currency = first.currency;
+ const currency = first.currency;
let value = first.value + Math.floor(first.fraction / fractionalBase);
if (value > Number.MAX_SAFE_INTEGER) {
return { amount: getMaxAmount(currency), saturated: true };
}
let fraction = first.fraction % fractionalBase;
- for (let x of rest) {
+ for (const x of rest) {
if (x.currency !== currency) {
throw Error(`Mismatched currency: ${x.currency} and ${currency}`);
}
@@ -665,11 +665,11 @@ export namespace Amounts {
export function sub(a: AmountJson, ...rest: AmountJson[]): Result {
- let currency = a.currency;
+ const currency = a.currency;
let value = a.value;
let fraction = a.fraction;
- for (let b of rest) {
+ for (const b of rest) {
if (b.currency !== currency) {
throw Error(`Mismatched currency: ${b.currency} and ${currency}`);
}
@@ -695,10 +695,10 @@ export namespace Amounts {
if (a.currency !== b.currency) {
throw Error(`Mismatched currency: ${a.currency} and ${b.currency}`);
}
- let av = a.value + Math.floor(a.fraction / fractionalBase);
- let af = a.fraction % fractionalBase;
- let bv = b.value + Math.floor(b.fraction / fractionalBase);
- let bf = b.fraction % fractionalBase;
+ const av = a.value + Math.floor(a.fraction / fractionalBase);
+ const af = a.fraction % fractionalBase;
+ const bv = b.value + Math.floor(b.fraction / fractionalBase);
+ const bf = b.fraction % fractionalBase;
switch (true) {
case av < bv:
return -1;
@@ -708,7 +708,7 @@ export namespace Amounts {
return -1;
case af > bf:
return 1;
- case af == bf:
+ case af === bf:
return 0;
default:
throw Error("assertion failed");
@@ -717,25 +717,25 @@ export namespace Amounts {
export function copy(a: AmountJson): AmountJson {
return {
- value: a.value,
- fraction: a.fraction,
currency: a.currency,
- }
+ fraction: a.fraction,
+ value: a.value,
+ };
}
export function divide(a: AmountJson, n: number): AmountJson {
- if (n == 0) {
+ if (n === 0) {
throw Error(`Division by 0`);
}
- if (n == 1) {
+ if (n === 1) {
return {value: a.value, fraction: a.fraction, currency: a.currency};
}
- let r = a.value % n;
+ const r = a.value % n;
return {
currency: a.currency,
- value: Math.floor(a.value / n),
fraction: Math.floor(((r * fractionalBase) + a.fraction) / n),
- }
+ value: Math.floor(a.value / n),
+ };
}
export function isNonZero(a: AmountJson) {
@@ -746,15 +746,15 @@ export namespace Amounts {
* Parse an amount like 'EUR:20.5' for 20 Euros and 50 ct.
*/
export function parse(s: string): AmountJson|undefined {
- let res = s.match(/([a-zA-Z0-9_*-]+):([0-9])+([.][0-9]+)?/);
+ const res = s.match(/([a-zA-Z0-9_*-]+):([0-9])+([.][0-9]+)?/);
if (!res) {
return undefined;
}
return {
currency: res[1],
- value: Number.parseInt(res[2]),
fraction: Math.round(fractionalBase * Number.parseFloat(res[3] || "0")),
- }
+ value: Number.parseInt(res[2]),
+ };
}
}
diff --git a/src/wallet-test.ts b/src/wallet-test.ts
index 2c3ed52d0..51a8497b7 100644
--- a/src/wallet-test.ts
+++ b/src/wallet-test.ts
@@ -1,135 +1,152 @@
+/*
+ This file is part of TALER
+ (C) 2017 Inria and 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, see <http://www.gnu.org/licenses/>
+ */
+
+
import {test} from "ava";
import * as types from "./types";
import * as wallet from "./wallet";
+
function a(x: string): types.AmountJson {
- let amt = types.Amounts.parse(x);
+ const amt = types.Amounts.parse(x);
if (!amt) {
throw Error("invalid amount");
}
return amt;
}
+
function fakeCwd(current: string, value: string, feeDeposit: string): wallet.CoinWithDenom {
return {
coin: {
- currentAmount: a(current),
- coinPub: "(mock)",
+ blindingKey: "(mock)",
coinPriv: "(mock)",
+ coinPub: "(mock)",
+ currentAmount: a(current),
denomPub: "(mock)",
denomSig: "(mock)",
exchangeBaseUrl: "(mock)",
- blindingKey: "(mock)",
reservePub: "(mock)",
status: types.CoinStatus.Fresh,
},
denom: {
- value: a(value),
- feeDeposit: a(feeDeposit),
denomPub: "(mock)",
denomPubHash: "(mock)",
- feeWithdraw: a("EUR:0.0"),
+ exchangeBaseUrl: "(mock)",
+ feeDeposit: a(feeDeposit),
feeRefresh: a("EUR:0.0"),
feeRefund: a("EUR:0.0"),
- stampStart: "(mock)",
- stampExpireWithdraw: "(mock)",
- stampExpireLegal: "(mock)",
- stampExpireDeposit: "(mock)",
+ feeWithdraw: a("EUR:0.0"),
+ isOffered: true,
masterSig: "(mock)",
+ stampExpireDeposit: "(mock)",
+ stampExpireLegal: "(mock)",
+ stampExpireWithdraw: "(mock)",
+ stampStart: "(mock)",
status: types.DenominationStatus.VerifiedGood,
- isOffered: true,
- exchangeBaseUrl: "(mock)",
+ value: a(value),
},
- }
+ };
}
-
-test("coin selection 1", t => {
- let cds: wallet.CoinWithDenom[] = [
+test("coin selection 1", (t) => {
+ const cds: wallet.CoinWithDenom[] = [
fakeCwd("EUR:1.0", "EUR:1.0", "EUR:0.1"),
fakeCwd("EUR:1.0", "EUR:1.0", "EUR:0.0"),
];
- let res = wallet.selectCoins(cds, a("EUR:2.0"), a("EUR:0.1"));
+ const res = wallet.selectCoins(cds, a("EUR:2.0"), a("EUR:0.1"));
if (!res) {
t.fail();
return;
}
- t.true(res.length == 2);
+ t.true(res.length === 2);
t.pass();
});
-test("coin selection 2", t => {
- let cds: wallet.CoinWithDenom[] = [
+test("coin selection 2", (t) => {
+ const cds: wallet.CoinWithDenom[] = [
fakeCwd("EUR:1.0", "EUR:1.0", "EUR:0.5"),
fakeCwd("EUR:1.0", "EUR:1.0", "EUR:0.0"),
// Merchant covers the fee, this one shouldn't be used
fakeCwd("EUR:1.0", "EUR:1.0", "EUR:0.0"),
];
- let res = wallet.selectCoins(cds, a("EUR:2.0"), a("EUR:0.5"));
+ const res = wallet.selectCoins(cds, a("EUR:2.0"), a("EUR:0.5"));
if (!res) {
t.fail();
return;
}
- t.true(res.length == 2);
+ t.true(res.length === 2);
t.pass();
});
-test("coin selection 3", t => {
- let cds: wallet.CoinWithDenom[] = [
+test("coin selection 3", (t) => {
+ const cds: wallet.CoinWithDenom[] = [
fakeCwd("EUR:1.0", "EUR:1.0", "EUR:0.5"),
fakeCwd("EUR:1.0", "EUR:1.0", "EUR:0.5"),
// this coin should be selected instead of previous one with fee
fakeCwd("EUR:1.0", "EUR:1.0", "EUR:0.0"),
];
- let res = wallet.selectCoins(cds, a("EUR:2.0"), a("EUR:0.5"));
+ const res = wallet.selectCoins(cds, a("EUR:2.0"), a("EUR:0.5"));
if (!res) {
t.fail();
return;
}
- t.true(res.length == 2);
+ t.true(res.length === 2);
t.pass();
});
-
-test("coin selection 4", t => {
- let cds: wallet.CoinWithDenom[] = [
+test("coin selection 4", (t) => {
+ const cds: wallet.CoinWithDenom[] = [
fakeCwd("EUR:1.0", "EUR:1.0", "EUR:0.5"),
fakeCwd("EUR:1.0", "EUR:1.0", "EUR:0.5"),
fakeCwd("EUR:1.0", "EUR:1.0", "EUR:0.5"),
];
- let res = wallet.selectCoins(cds, a("EUR:2.0"), a("EUR:0.2"));
+ const res = wallet.selectCoins(cds, a("EUR:2.0"), a("EUR:0.2"));
if (!res) {
t.fail();
return;
}
- t.true(res.length == 3);
+ t.true(res.length === 3);
t.pass();
});
-test("coin selection 5", t => {
- let cds: wallet.CoinWithDenom[] = [
+test("coin selection 5", (t) => {
+ const cds: wallet.CoinWithDenom[] = [
fakeCwd("EUR:1.0", "EUR:1.0", "EUR:0.5"),
fakeCwd("EUR:1.0", "EUR:1.0", "EUR:0.5"),
fakeCwd("EUR:1.0", "EUR:1.0", "EUR:0.5"),
];
- let res = wallet.selectCoins(cds, a("EUR:4.0"), a("EUR:0.2"));
+ const res = wallet.selectCoins(cds, a("EUR:4.0"), a("EUR:0.2"));
t.true(!res);
t.pass();
});
-test("coin selection 6", t => {
- let cds: wallet.CoinWithDenom[] = [
+test("coin selection 6", (t) => {
+ const cds: wallet.CoinWithDenom[] = [
fakeCwd("EUR:1.0", "EUR:1.0", "EUR:0.5"),
fakeCwd("EUR:1.0", "EUR:1.0", "EUR:0.5"),
];
- let res = wallet.selectCoins(cds, a("EUR:2.0"), a("EUR:0.2"));
+ const res = wallet.selectCoins(cds, a("EUR:2.0"), a("EUR:0.2"));
t.true(!res);
t.pass();
});
diff --git a/src/wallet.ts b/src/wallet.ts
index a2a9e83f5..b21cdbd96 100644
--- a/src/wallet.ts
+++ b/src/wallet.ts
@@ -22,57 +22,58 @@
/**
* Imports.
*/
+import {Checkable} from "./checkable";
+import {CryptoApi} from "./crypto/cryptoApi";
+import {
+ amountToPretty,
+ canonicalJson,
+ canonicalizeBaseUrl,
+ deepEquals,
+ flatMap,
+ getTalerStampSec,
+} from "./helpers";
+import {
+ HttpRequestLibrary,
+ HttpResponse,
+ RequestException,
+} from "./http";
+import {
+ AbortTransaction,
+ Index,
+ JoinLeftResult,
+ JoinResult,
+ QueryRoot,
+ Store,
+} from "./query";
import {
AmountJson,
Amounts,
- CoinRecord,
+ Auditor,
+ AuditorRecord,
CoinPaySig,
+ CoinRecord,
+ CoinStatus,
Contract,
CreateReserveResponse,
+ CurrencyRecord,
Denomination,
+ DenominationRecord,
+ DenominationStatus,
ExchangeHandle,
ExchangeRecord,
+ ExchangeWireFeesRecord,
Notifier,
PayCoinInfo,
+ PaybackConfirmation,
PreCoinRecord,
RefreshSessionRecord,
ReserveCreationInfo,
ReserveRecord,
- CurrencyRecord,
- Auditor,
- AuditorRecord,
WalletBalance,
WalletBalanceEntry,
WireFee,
- ExchangeWireFeesRecord,
WireInfo,
- DenominationRecord,
- DenominationStatus,
- CoinStatus,
- PaybackConfirmation,
} from "./types";
-import {
- HttpRequestLibrary,
- HttpResponse,
- RequestException,
-} from "./http";
-import {
- AbortTransaction,
- Index,
- JoinResult,
- QueryRoot,
- Store, JoinLeftResult,
-} from "./query";
-import {Checkable} from "./checkable";
-import {
- amountToPretty,
- canonicalizeBaseUrl,
- canonicalJson,
- deepEquals,
- flatMap,
- getTalerStampSec,
-} from "./helpers";
-import {CryptoApi} from "./crypto/cryptoApi";
import URI = require("urijs");
@@ -272,33 +273,31 @@ export interface ConfigRecord {
}
-
const builtinCurrencies: CurrencyRecord[] = [
{
- name: "KUDOS",
- fractionalDigits: 2,
auditors: [
{
+ auditorPub: "XN9KMN5G2KGPCAN0E89MM5HE8FV4WBWA9KDTMTDR817MWBCYA7H0",
baseUrl: "https://auditor.demo.taler.net/",
expirationStamp: (new Date(2027, 1)).getTime(),
- auditorPub: "XN9KMN5G2KGPCAN0E89MM5HE8FV4WBWA9KDTMTDR817MWBCYA7H0",
},
],
exchanges: [],
+ fractionalDigits: 2,
+ name: "KUDOS",
},
{
- name: "PUDOS",
- fractionalDigits: 2,
auditors: [
],
exchanges: [
{ baseUrl: "https://exchange.test.taler.net/", priority: 0 },
],
+ fractionalDigits: 2,
+ name: "PUDOS",
},
];
-
// FIXME: these functions should be dependency-injected
// into the wallet, as this is chrome specific => bad
@@ -312,17 +311,17 @@ function setInterval(f: any, t: number) {
function isWithdrawableDenom(d: DenominationRecord) {
- const now_sec = (new Date).getTime() / 1000;
- const stamp_withdraw_sec = getTalerStampSec(d.stampExpireWithdraw);
- if (stamp_withdraw_sec == null) {
+ const nowSec = (new Date()).getTime() / 1000;
+ const stampWithdrawSec = getTalerStampSec(d.stampExpireWithdraw);
+ if (stampWithdrawSec === null) {
return false;
}
- const stamp_start_sec = getTalerStampSec(d.stampStart);
- if (stamp_start_sec == null) {
+ const stampStartSec = getTalerStampSec(d.stampStart);
+ if (stampStartSec === null) {
return false;
}
// Withdraw if still possible to withdraw within a minute
- if ((stamp_withdraw_sec + 60 > now_sec) && (now_sec >= stamp_start_sec)) {
+ if ((stampWithdrawSec + 60 > nowSec) && (nowSec >= stampStartSec)) {
return true;
}
return false;
@@ -333,31 +332,30 @@ export type CoinSelectionResult = {exchangeUrl: string, cds: CoinWithDenom[]}|un
export function selectCoins(cds: CoinWithDenom[], paymentAmount: AmountJson,
depositFeeLimit: AmountJson): CoinWithDenom[]|undefined {
- if (cds.length == 0) {
+ if (cds.length === 0) {
return undefined;
}
// Sort by ascending deposit fee
cds.sort((o1, o2) => Amounts.cmp(o1.denom.feeDeposit,
o2.denom.feeDeposit));
- let currency = cds[0].denom.value.currency;
- let cdsResult: CoinWithDenom[] = [];
+ const currency = cds[0].denom.value.currency;
+ const cdsResult: CoinWithDenom[] = [];
let accFee: AmountJson = Amounts.getZero(currency);
let accAmount: AmountJson = Amounts.getZero(currency);
let isBelowFee = false;
let coversAmount = false;
let coversAmountWithFee = false;
- for (let i = 0; i < cds.length; i++) {
- let {coin, denom} = cds[i];
+ for (const {coin, denom} of cds) {
if (coin.suspended) {
continue;
}
- if (coin.status != CoinStatus.Fresh) {
+ if (coin.status !== CoinStatus.Fresh) {
continue;
}
if (Amounts.cmp(denom.feeDeposit, coin.currentAmount) >= 0) {
continue;
}
- cdsResult.push(cds[i]);
+ cdsResult.push({coin, denom});
accFee = Amounts.add(denom.feeDeposit, accFee).amount;
accAmount = Amounts.add(coin.currentAmount, accAmount).amount;
coversAmount = Amounts.cmp(accAmount, paymentAmount) >= 0;
@@ -391,8 +389,8 @@ function getWithdrawDenomList(amountAvailable: AmountJson,
// is useful ...
for (let i = 0; i < 1000; i++) {
let found = false;
- for (let d of denoms) {
- let cost = Amounts.add(d.value, d.feeWithdraw).amount;
+ for (const d of denoms) {
+ const cost = Amounts.add(d.value, d.feeWithdraw).amount;
if (Amounts.cmp(remaining, cost) < 0) {
continue;
}
@@ -415,7 +413,7 @@ export namespace Stores {
super("exchanges", {keyPath: "baseUrl"});
}
- pubKeyIndex = new Index<string,ExchangeRecord>(this, "pubKey", "masterPublicKey");
+ pubKeyIndex = new Index<string, ExchangeRecord>(this, "pubKey", "masterPublicKey");
}
class NonceStore extends Store<NonceRecord> {
@@ -429,26 +427,26 @@ export namespace Stores {
super("coins", {keyPath: "coinPub"});
}
- exchangeBaseUrlIndex = new Index<string,CoinRecord>(this, "exchangeBaseUrl", "exchangeBaseUrl");
- denomPubIndex = new Index<string,CoinRecord>(this, "denomPub", "denomPub");
+ exchangeBaseUrlIndex = new Index<string, CoinRecord>(this, "exchangeBaseUrl", "exchangeBaseUrl");
+ denomPubIndex = new Index<string, CoinRecord>(this, "denomPub", "denomPub");
}
class HistoryStore extends Store<HistoryRecord> {
constructor() {
super("history", {
+ autoIncrement: true,
keyPath: "id",
- autoIncrement: true
});
}
- timestampIndex = new Index<number,HistoryRecord>(this, "timestamp", "timestamp");
+ timestampIndex = new Index<number, HistoryRecord>(this, "timestamp", "timestamp");
}
class OffersStore extends Store<OfferRecord> {
constructor() {
super("offers", {
+ autoIncrement: true,
keyPath: "id",
- autoIncrement: true
});
}
}
@@ -458,8 +456,8 @@ export namespace Stores {
super("transactions", {keyPath: "contractHash"});
}
- fulfillmentUrlIndex = new Index<string,TransactionRecord>(this, "fulfillment_url", "contract.fulfillment_url");
- orderIdIndex = new Index<string,TransactionRecord>(this, "order_id", "contract.order_id");
+ fulfillmentUrlIndex = new Index<string, TransactionRecord>(this, "fulfillment_url", "contract.fulfillment_url");
+ orderIdIndex = new Index<string, TransactionRecord>(this, "order_id", "contract.order_id");
}
class DenominationsStore extends Store<DenominationRecord> {
@@ -469,7 +467,7 @@ export namespace Stores {
{keyPath: ["exchangeBaseUrl", "denomPub"] as any as IDBKeyPath});
}
- denomPubHashIndex = new Index<string,DenominationRecord>(this, "denomPubHash", "denomPubHash");
+ denomPubHashIndex = new Index<string, DenominationRecord>(this, "denomPubHash", "denomPubHash");
exchangeBaseUrlIndex = new Index<string, DenominationRecord>(this, "exchangeBaseUrl", "exchangeBaseUrl");
denomPubIndex = new Index<string, DenominationRecord>(this, "denomPub", "denomPub");
}
@@ -491,19 +489,31 @@ export namespace Stores {
super("exchangeWireFees", {keyPath: "exchangeBaseUrl"});
}
}
- export const exchanges: ExchangeStore = new ExchangeStore();
- export const exchangeWireFees: ExchangeWireFeesStore = new ExchangeWireFeesStore();
- export const nonces: NonceStore = new NonceStore();
- export const transactions: TransactionsStore = new TransactionsStore();
- export const reserves: Store<ReserveRecord> = new Store<ReserveRecord>("reserves", {keyPath: "reserve_pub"});
- export const coins: CoinsStore = new CoinsStore();
- export const refresh: Store<RefreshSessionRecord> = new Store<RefreshSessionRecord>("refresh", {keyPath: "meltCoinPub"});
- export const history: HistoryStore = new HistoryStore();
- export const offers: OffersStore = new OffersStore();
- export const precoins: Store<PreCoinRecord> = new Store<PreCoinRecord>("precoins", {keyPath: "coinPub"});
- export const denominations: DenominationsStore = new DenominationsStore();
- export const currencies: CurrenciesStore = new CurrenciesStore();
- export const config: ConfigStore = new ConfigStore();
+ export const exchanges = new ExchangeStore();
+ export const exchangeWireFees = new ExchangeWireFeesStore();
+ export const nonces = new NonceStore();
+ export const transactions = new TransactionsStore();
+ export const reserves = new Store<ReserveRecord>("reserves", {keyPath: "reserve_pub"});
+ export const coins = new CoinsStore();
+ export const refresh = new Store<RefreshSessionRecord>("refresh", {keyPath: "meltCoinPub"});
+ export const history = new HistoryStore();
+ export const offers = new OffersStore();
+ export const precoins = new Store<PreCoinRecord>("precoins", {keyPath: "coinPub"});
+ export const denominations = new DenominationsStore();
+ export const currencies = new CurrenciesStore();
+ export const config = new ConfigStore();
+}
+
+
+interface CoinsForPaymentArgs {
+ allowedAuditors: Auditor[];
+ allowedExchanges: ExchangeHandle[];
+ depositFeeLimit: AmountJson;
+ paymentAmount: AmountJson;
+ wireFeeAmortization: number;
+ wireFeeLimit: AmountJson;
+ wireFeeTime: number;
+ wireMethod: string;
}
@@ -543,10 +553,10 @@ export class Wallet {
}
private async fillDefaults() {
- let onTrue = (r: QueryRoot) => {
+ const onTrue = (r: QueryRoot) => {
console.log("defaults already applied");
};
- let onFalse = (r: QueryRoot) => {
+ const onFalse = (r: QueryRoot) => {
console.log("applying defaults");
r.put(Stores.config, {key: "currencyDefaultsApplied", value: true})
.putAll(Stores.currencies, builtinCurrencies)
@@ -555,7 +565,7 @@ export class Wallet {
await (
this.q()
.iter(Stores.config)
- .filter(x => x.key == "currencyDefaultsApplied")
+ .filter((x) => x.key === "currencyDefaultsApplied")
.first()
.cond((x) => x && x.value, onTrue, onFalse)
);
@@ -569,7 +579,7 @@ export class Wallet {
private stopOperation(operationId: string) {
this.runningOperations.delete(operationId);
- if (this.runningOperations.size == 0) {
+ if (this.runningOperations.size === 0) {
this.badge.stopBusy();
}
}
@@ -577,12 +587,12 @@ export class Wallet {
async updateExchanges(): Promise<void> {
console.log("updating exchanges");
- let exchangesUrls = await this.q()
- .iter(Stores.exchanges)
- .map((e) => e.baseUrl)
- .toArray();
+ const exchangesUrls = await this.q()
+ .iter(Stores.exchanges)
+ .map((e) => e.baseUrl)
+ .toArray();
- for (let url of exchangesUrls) {
+ for (const url of exchangesUrls) {
this.updateExchangeFromUrl(url)
.catch((e) => {
console.error("updating exchange failed", e);
@@ -621,7 +631,7 @@ export class Wallet {
this.q()
.iter(Stores.coins)
.reduce((c: CoinRecord) => {
- if (c.status == CoinStatus.Dirty) {
+ if (c.status === CoinStatus.Dirty) {
console.log("resuming pending refresh for coin", c);
this.refresh(c.coinPub);
}
@@ -633,23 +643,28 @@ export class Wallet {
* Get exchanges and associated coins that are still spendable,
* but only if the sum the coins' remaining value exceeds the payment amount.
*/
- private async getCoinsForPayment(paymentAmount: AmountJson,
- wireMethod: string,
- wireFeeTime: number,
- depositFeeLimit: AmountJson,
- wireFeeLimit: AmountJson,
- wireFeeAmortization: number,
- allowedExchanges: ExchangeHandle[],
- allowedAuditors: Auditor[]): Promise<CoinSelectionResult> {
-
- let exchanges = await this.q().iter(Stores.exchanges).toArray();
-
- for (let exchange of exchanges) {
+ private async getCoinsForPayment(args: CoinsForPaymentArgs): Promise<CoinSelectionResult> {
+ const {
+ allowedAuditors,
+ allowedExchanges,
+ depositFeeLimit,
+ paymentAmount,
+ wireFeeAmortization,
+ wireFeeLimit,
+ wireFeeTime,
+ wireMethod,
+ } = args;
+
+ let remainingAmount = paymentAmount;
+
+ const exchanges = await this.q().iter(Stores.exchanges).toArray();
+
+ for (const exchange of exchanges) {
let isOkay: boolean = false;
// is the exchange explicitly allowed?
- for (let allowedExchange of allowedExchanges) {
- if (allowedExchange.master_pub == exchange.masterPublicKey) {
+ for (const allowedExchange of allowedExchanges) {
+ if (allowedExchange.master_pub === exchange.masterPublicKey) {
isOkay = true;
break;
}
@@ -657,9 +672,9 @@ export class Wallet {
// is the exchange allowed because of one of its auditors?
if (!isOkay) {
- for (let allowedAuditor of allowedAuditors) {
- for (let auditor of exchange.auditors) {
- if (auditor.auditor_pub == allowedAuditor.auditor_pub) {
+ for (const allowedAuditor of allowedAuditors) {
+ for (const auditor of exchange.auditors) {
+ if (auditor.auditor_pub === allowedAuditor.auditor_pub) {
isOkay = true;
break;
}
@@ -674,53 +689,52 @@ export class Wallet {
continue;
}
- let coins: CoinRecord[] = await this.q()
+ const coins: CoinRecord[] = await this.q()
.iterIndex(Stores.coins.exchangeBaseUrlIndex,
exchange.baseUrl)
.toArray();
- if (!coins || coins.length == 0) {
+ if (!coins || coins.length === 0) {
continue;
}
// Denomination of the first coin, we assume that all other
// coins have the same currency
- let firstDenom = await this.q().get(Stores.denominations,
- [
- exchange.baseUrl,
- coins[0].denomPub
- ]);
+ const firstDenom = await this.q().get(Stores.denominations,
+ [
+ exchange.baseUrl,
+ coins[0].denomPub,
+ ]);
if (!firstDenom) {
throw Error("db inconsistent");
}
- let currency = firstDenom.value.currency;
- let cds: CoinWithDenom[] = [];
- for (let i = 0; i < coins.length; i++) {
- let coin = coins[i];
- let denom = await this.q().get(Stores.denominations,
+ const currency = firstDenom.value.currency;
+ const cds: CoinWithDenom[] = [];
+ for (const coin of coins) {
+ const denom = await this.q().get(Stores.denominations,
[exchange.baseUrl, coin.denomPub]);
if (!denom) {
throw Error("db inconsistent");
}
- if (denom.value.currency != currency) {
+ if (denom.value.currency !== currency) {
console.warn(`same pubkey for different currencies at exchange ${exchange.baseUrl}`);
continue;
}
if (coin.suspended) {
continue;
}
- if (coin.status != CoinStatus.Fresh) {
+ if (coin.status !== CoinStatus.Fresh) {
continue;
}
cds.push({coin, denom});
}
- let fees = await this.q().get(Stores.exchangeWireFees, exchange.baseUrl);
+ const fees = await this.q().get(Stores.exchangeWireFees, exchange.baseUrl);
if (!fees) {
console.error("no fees found for exchange", exchange);
continue;
}
- let wireFee: AmountJson|undefined = undefined;
- for (let fee of (fees.feesForType[wireMethod] || [])) {
+ let wireFee: AmountJson|undefined;
+ for (const fee of (fees.feesForType[wireMethod] || [])) {
if (fee.startStamp >= wireFeeTime && fee.endStamp <= wireFeeTime) {
wireFee = fee.wireFee;
break;
@@ -728,18 +742,18 @@ export class Wallet {
}
if (wireFee) {
- let amortizedWireFee = Amounts.divide(wireFee, wireFeeAmortization);
+ const amortizedWireFee = Amounts.divide(wireFee, wireFeeAmortization);
if (Amounts.cmp(wireFeeLimit, amortizedWireFee) < 0) {
- paymentAmount = Amounts.add(amortizedWireFee, paymentAmount).amount;
+ remainingAmount = Amounts.add(amortizedWireFee, remainingAmount).amount;
}
}
- let res = selectCoins(cds, paymentAmount, depositFeeLimit);
+ const res = selectCoins(cds, remainingAmount, depositFeeLimit);
if (res) {
return {
- exchangeUrl: exchange.baseUrl,
cds: res,
- }
+ exchangeUrl: exchange.baseUrl,
+ };
}
}
return undefined;
@@ -753,31 +767,31 @@ export class Wallet {
private async recordConfirmPay(offer: OfferRecord,
payCoinInfo: PayCoinInfo,
chosenExchange: string): Promise<void> {
- let payReq: PayReq = {
+ const payReq: PayReq = {
coins: payCoinInfo.map((x) => x.sig),
+ exchange: chosenExchange,
merchant_pub: offer.contract.merchant_pub,
order_id: offer.contract.order_id,
- exchange: chosenExchange,
};
- let t: TransactionRecord = {
- contractHash: offer.H_contract,
+ const t: TransactionRecord = {
contract: offer.contract,
- payReq: payReq,
- merchantSig: offer.merchant_sig,
+ contractHash: offer.H_contract,
finished: false,
+ merchantSig: offer.merchant_sig,
+ payReq,
};
- let historyEntry: HistoryRecord = {
- type: "pay",
- timestamp: (new Date).getTime(),
- subjectId: `contract-${offer.H_contract}`,
+ const historyEntry: HistoryRecord = {
detail: {
- merchantName: offer.contract.merchant.name,
amount: offer.contract.amount,
contractHash: offer.H_contract,
fulfillmentUrl: offer.contract.fulfillment_url,
+ merchantName: offer.contract.merchant.name,
},
- level: HistoryLevel.User
+ level: HistoryLevel.User,
+ subjectId: `contract-${offer.H_contract}`,
+ timestamp: (new Date()).getTime(),
+ type: "pay",
};
await this.q()
@@ -798,7 +812,7 @@ export class Wallet {
async saveOffer(offer: OfferRecord): Promise<number> {
console.log(`saving offer in wallet.ts`);
- let id = await this.q().putWithResult(Stores.offers, offer);
+ const id = await this.q().putWithResult(Stores.offers, offer);
this.notifier.notify();
console.log(`saved offer with id ${id}`);
if (typeof id !== "number") {
@@ -815,21 +829,23 @@ export class Wallet {
async confirmPay(offer: OfferRecord): Promise<any> {
console.log("executing confirmPay");
- let transaction = await this.q().get(Stores.transactions, offer.H_contract);
+ const transaction = await this.q().get(Stores.transactions, offer.H_contract);
if (transaction) {
// Already payed ...
return {};
}
- let res = await this.getCoinsForPayment(offer.contract.amount,
- offer.contract.wire_method,
- getTalerStampSec(offer.contract.timestamp) || 0,
- offer.contract.max_fee,
- offer.contract.max_wire_fee || Amounts.getZero(offer.contract.amount.currency),
- offer.contract.wire_fee_amortization || 1,
- offer.contract.exchanges,
- offer.contract.auditors);
+ const res = await this.getCoinsForPayment({
+ allowedAuditors: offer.contract.auditors,
+ allowedExchanges: offer.contract.exchanges,
+ depositFeeLimit: offer.contract.max_fee,
+ paymentAmount: offer.contract.amount,
+ wireFeeAmortization: offer.contract.wire_fee_amortization || 1,
+ wireFeeLimit: offer.contract.max_wire_fee || Amounts.getZero(offer.contract.amount.currency),
+ wireFeeTime: getTalerStampSec(offer.contract.timestamp) || 0,
+ wireMethod: offer.contract.wire_method,
+ });
console.log("max_fee", offer.contract.max_fee);
console.log("coin selection result", res);
@@ -840,9 +856,9 @@ export class Wallet {
error: "coins-insufficient",
};
}
- let {exchangeUrl, cds} = res;
+ const {exchangeUrl, cds} = res;
- let ds = await this.cryptoApi.signDeposit(offer, cds);
+ const ds = await this.cryptoApi.signDeposit(offer, cds);
await this.recordConfirmPay(offer,
ds,
exchangeUrl);
@@ -856,20 +872,22 @@ export class Wallet {
*/
async checkPay(offer: OfferRecord): Promise<any> {
// First check if we already payed for it.
- let transaction = await this.q().get(Stores.transactions, offer.H_contract);
+ const transaction = await this.q().get(Stores.transactions, offer.H_contract);
if (transaction) {
return {isPayed: true};
}
// If not already payed, check if we could pay for it.
- let res = await this.getCoinsForPayment(offer.contract.amount,
- offer.contract.wire_method,
- getTalerStampSec(offer.contract.timestamp) || 0,
- offer.contract.max_fee,
- offer.contract.max_wire_fee || Amounts.getZero(offer.contract.amount.currency),
- offer.contract.wire_fee_amortization || 1,
- offer.contract.exchanges,
- offer.contract.auditors);
+ const res = await this.getCoinsForPayment({
+ allowedAuditors: offer.contract.auditors,
+ allowedExchanges: offer.contract.exchanges,
+ depositFeeLimit: offer.contract.max_fee,
+ paymentAmount: offer.contract.amount,
+ wireFeeAmortization: offer.contract.wire_fee_amortization || 1,
+ wireFeeLimit: offer.contract.max_wire_fee || Amounts.getZero(offer.contract.amount.currency),
+ wireFeeTime: getTalerStampSec(offer.contract.timestamp) || 0,
+ wireMethod: offer.contract.wire_method,
+ });
if (!res) {
console.log("not confirming payment, insufficient coins");
@@ -894,14 +912,14 @@ export class Wallet {
console.log("query for payment failed");
return {
success: false,
- }
+ };
}
console.log("query for payment succeeded:", t);
- let resp = {
- success: true,
- payReq: t.payReq,
+ const resp = {
H_contract: t.contractHash,
contract: t.contract,
+ payReq: t.payReq,
+ success: true,
};
return resp;
}
@@ -917,29 +935,28 @@ export class Wallet {
this.startOperation(opId);
try {
- let exchange = await this.updateExchangeFromUrl(reserveRecord.exchange_base_url);
- let reserve = await this.updateReserve(reserveRecord.reserve_pub);
- let n = await this.depleteReserve(reserve);
+ const exchange = await this.updateExchangeFromUrl(reserveRecord.exchange_base_url);
+ const reserve = await this.updateReserve(reserveRecord.reserve_pub);
+ const n = await this.depleteReserve(reserve);
- if (n != 0) {
- let depleted: HistoryRecord = {
- type: "depleted-reserve",
- subjectId: `reserve-progress-${reserveRecord.reserve_pub}`,
- timestamp: (new Date).getTime(),
+ if (n !== 0) {
+ const depleted: HistoryRecord = {
detail: {
+ currentAmount: reserveRecord.current_amount,
exchangeBaseUrl: reserveRecord.exchange_base_url,
- reservePub: reserveRecord.reserve_pub,
requestedAmount: reserveRecord.requested_amount,
- currentAmount: reserveRecord.current_amount,
+ reservePub: reserveRecord.reserve_pub,
},
- level: HistoryLevel.User
+ level: HistoryLevel.User,
+ subjectId: `reserve-progress-${reserveRecord.reserve_pub}`,
+ timestamp: (new Date()).getTime(),
+ type: "depleted-reserve",
};
await this.q().put(Stores.history, depleted).finish();
}
} catch (e) {
// random, exponential backoff truncated at 3 minutes
- let nextDelay = Math.min(2 * retryDelayMs + retryDelayMs * Math.random(),
- 3000 * 60);
+ const nextDelay = Math.min(2 * retryDelayMs + retryDelayMs * Math.random(), 3000 * 60);
console.warn(`Failed to deplete reserve, trying again in ${retryDelayMs} ms`);
setTimeout(() => this.processReserve(reserveRecord, nextDelay),
retryDelayMs);
@@ -980,9 +997,7 @@ export class Wallet {
console.log(`before committing coin: current ${amountToPretty(r.current_amount!)}, precoin: ${amountToPretty(
r.precoin_amount)})}`);
- let x = Amounts.sub(r.precoin_amount,
- preCoin.coinValue,
- denom.feeWithdraw);
+ const x = Amounts.sub(r.precoin_amount, preCoin.coinValue, denom.feeWithdraw);
if (x.saturated) {
console.error("database inconsistent");
throw AbortTransaction;
@@ -992,12 +1007,12 @@ export class Wallet {
};
const historyEntry: HistoryRecord = {
- type: "withdraw",
- timestamp: (new Date).getTime(),
- level: HistoryLevel.Expert,
detail: {
coinPub: coin.coinPub,
- }
+ },
+ level: HistoryLevel.Expert,
+ timestamp: (new Date()).getTime(),
+ type: "withdraw",
};
await this.q()
@@ -1013,10 +1028,12 @@ export class Wallet {
retryDelayMs,
"ms", e);
// exponential backoff truncated at one minute
- let nextRetryDelayMs = Math.min(retryDelayMs * 2, 5 * 60 * 1000);
+ const nextRetryDelayMs = Math.min(retryDelayMs * 2, 5 * 60 * 1000);
setTimeout(() => this.processPreCoin(preCoin, nextRetryDelayMs),
retryDelayMs);
- this.processPreCoinThrottle[preCoin.exchangeBaseUrl] = (this.processPreCoinThrottle[preCoin.exchangeBaseUrl] || 0) + 1;
+
+ const currentThrottle = this.processPreCoinThrottle[preCoin.exchangeBaseUrl] || 0;
+ this.processPreCoinThrottle[preCoin.exchangeBaseUrl] = currentThrottle + 1;
setTimeout(() => {this.processPreCoinThrottle[preCoin.exchangeBaseUrl]--; }, retryDelayMs);
} finally {
this.processPreCoinConcurrent--;
@@ -1031,44 +1048,44 @@ export class Wallet {
* audited nor trusted already.
*/
async createReserve(req: CreateReserveRequest): Promise<CreateReserveResponse> {
- let keypair = await this.cryptoApi.createEddsaKeypair();
- const now = (new Date).getTime();
+ const keypair = await this.cryptoApi.createEddsaKeypair();
+ const now = (new Date()).getTime();
const canonExchange = canonicalizeBaseUrl(req.exchange);
const reserveRecord: ReserveRecord = {
- hasPayback: false,
- reserve_pub: keypair.pub,
- reserve_priv: keypair.priv,
- exchange_base_url: canonExchange,
+ confirmed: false,
created: now,
- last_query: null,
current_amount: null,
- requested_amount: req.amount,
- confirmed: false,
+ exchange_base_url: canonExchange,
+ hasPayback: false,
+ last_query: null,
precoin_amount: Amounts.getZero(req.amount.currency),
+ requested_amount: req.amount,
+ reserve_priv: keypair.priv,
+ reserve_pub: keypair.pub,
};
const historyEntry = {
- type: "create-reserve",
- level: HistoryLevel.Expert,
- timestamp: now,
- subjectId: `reserve-progress-${reserveRecord.reserve_pub}`,
detail: {
requestedAmount: req.amount,
reservePub: reserveRecord.reserve_pub,
- }
+ },
+ level: HistoryLevel.Expert,
+ subjectId: `reserve-progress-${reserveRecord.reserve_pub}`,
+ timestamp: now,
+ type: "create-reserve",
};
- let exchangeInfo = await this.updateExchangeFromUrl(req.exchange);
- let {isAudited, isTrusted} = await this.getExchangeTrust(exchangeInfo);
+ const exchangeInfo = await this.updateExchangeFromUrl(req.exchange);
+ const {isAudited, isTrusted} = await this.getExchangeTrust(exchangeInfo);
let currencyRecord = await this.q().get(Stores.currencies, exchangeInfo.currency);
if (!currencyRecord) {
currencyRecord = {
- name: exchangeInfo.currency,
- fractionalDigits: 2,
- exchanges: [],
auditors: [],
- }
+ exchanges: [],
+ fractionalDigits: 2,
+ name: exchangeInfo.currency,
+ };
}
if (!isAudited && !isTrusted) {
@@ -1081,7 +1098,7 @@ export class Wallet {
.put(Stores.history, historyEntry)
.finish();
- let r: CreateReserveResponse = {
+ const r: CreateReserveResponse = {
exchange: canonExchange,
reservePub: keypair.pub,
};
@@ -1099,8 +1116,8 @@ export class Wallet {
* an unconfirmed reserve should be hidden.
*/
async confirmReserve(req: ConfirmReserveRequest): Promise<void> {
- const now = (new Date).getTime();
- let reserve: ReserveRecord|undefined = await (
+ const now = (new Date()).getTime();
+ const reserve: ReserveRecord|undefined = await (
this.q().get<ReserveRecord>(Stores.reserves,
req.reservePub));
if (!reserve) {
@@ -1109,15 +1126,15 @@ export class Wallet {
}
console.log("reserve confirmed");
const historyEntry: HistoryRecord = {
- type: "confirm-reserve",
- timestamp: now,
- subjectId: `reserve-progress-${reserve.reserve_pub}`,
detail: {
exchangeBaseUrl: reserve.exchange_base_url,
- reservePub: req.reservePub,
requestedAmount: reserve.requested_amount,
+ reservePub: req.reservePub,
},
level: HistoryLevel.User,
+ subjectId: `reserve-progress-${reserve.reserve_pub}`,
+ timestamp: now,
+ type: "confirm-reserve",
};
reserve.confirmed = true;
await this.q()
@@ -1131,40 +1148,40 @@ export class Wallet {
private async withdrawExecute(pc: PreCoinRecord): Promise<CoinRecord> {
- let reserve = await this.q().get<ReserveRecord>(Stores.reserves,
+ const reserve = await this.q().get<ReserveRecord>(Stores.reserves,
pc.reservePub);
if (!reserve) {
throw Error("db inconsistent");
}
- let wd: any = {};
+ const wd: any = {};
wd.denom_pub = pc.denomPub;
wd.reserve_pub = pc.reservePub;
wd.reserve_sig = pc.withdrawSig;
wd.coin_ev = pc.coinEv;
- let reqUrl = (new URI("reserve/withdraw")).absoluteTo(reserve.exchange_base_url);
- let resp = await this.http.postJson(reqUrl.href(), wd);
+ const reqUrl = (new URI("reserve/withdraw")).absoluteTo(reserve.exchange_base_url);
+ const resp = await this.http.postJson(reqUrl.href(), wd);
- if (resp.status != 200) {
+ if (resp.status !== 200) {
throw new RequestException({
hint: "Withdrawal failed",
- status: resp.status
+ status: resp.status,
});
}
- let r = JSON.parse(resp.responseText);
- let denomSig = await this.cryptoApi.rsaUnblind(r.ev_sig,
+ const r = JSON.parse(resp.responseText);
+ const denomSig = await this.cryptoApi.rsaUnblind(r.ev_sig,
pc.blindingKey,
pc.denomPub);
- let coin: CoinRecord = {
- reservePub: pc.reservePub,
- coinPub: pc.coinPub,
- coinPriv: pc.coinPriv,
- denomPub: pc.denomPub,
- denomSig: denomSig,
+ const coin: CoinRecord = {
blindingKey: pc.blindingKey,
+ coinPriv: pc.coinPriv,
+ coinPub: pc.coinPub,
currentAmount: pc.coinValue,
+ denomPub: pc.denomPub,
+ denomSig,
exchangeBaseUrl: pc.exchangeBaseUrl,
+ reservePub: pc.reservePub,
status: CoinStatus.Fresh,
};
return coin;
@@ -1179,25 +1196,24 @@ export class Wallet {
if (!reserve.current_amount) {
throw Error("can't withdraw when amount is unknown");
}
- let currentAmount = reserve.current_amount;
- if (!currentAmount) {
+ const withdrawAmount = reserve.current_amount;
+ if (!withdrawAmount) {
throw Error("can't withdraw when amount is unknown");
}
- let denomsForWithdraw = await this.getVerifiedWithdrawDenomList(reserve.exchange_base_url,
- currentAmount);
+ const denomsForWithdraw = await this.getVerifiedWithdrawDenomList(reserve.exchange_base_url, withdrawAmount);
console.log(`withdrawing ${denomsForWithdraw.length} coins`);
- let ps = denomsForWithdraw.map(async(denom) => {
+ const ps = denomsForWithdraw.map(async(denom) => {
function mutateReserve(r: ReserveRecord): ReserveRecord {
- let currentAmount = r.current_amount;
+ const currentAmount = r.current_amount;
if (!currentAmount) {
throw Error("can't withdraw when amount is unknown");
}
r.precoin_amount = Amounts.add(r.precoin_amount,
denom.value,
denom.feeWithdraw).amount;
- let result = Amounts.sub(currentAmount,
+ const result = Amounts.sub(currentAmount,
denom.value,
denom.feeWithdraw);
if (result.saturated) {
@@ -1212,7 +1228,7 @@ export class Wallet {
return r;
}
- let preCoin = await this.cryptoApi
+ const preCoin = await this.cryptoApi
.createPreCoin(denom, reserve);
await this.q()
.put(Stores.precoins, preCoin)
@@ -1230,34 +1246,34 @@ export class Wallet {
* by quering the reserve's exchange.
*/
private async updateReserve(reservePub: string): Promise<ReserveRecord> {
- let reserve = await this.q()
+ const reserve = await this.q()
.get<ReserveRecord>(Stores.reserves, reservePub);
if (!reserve) {
throw Error("reserve not in db");
}
- let reqUrl = new URI("reserve/status").absoluteTo(reserve.exchange_base_url);
- reqUrl.query({'reserve_pub': reservePub});
- let resp = await this.http.get(reqUrl.href());
- if (resp.status != 200) {
+ const reqUrl = new URI("reserve/status").absoluteTo(reserve.exchange_base_url);
+ reqUrl.query({reserve_pub: reservePub});
+ const resp = await this.http.get(reqUrl.href());
+ if (resp.status !== 200) {
throw Error();
}
- let reserveInfo = JSON.parse(resp.responseText);
+ const reserveInfo = JSON.parse(resp.responseText);
if (!reserveInfo) {
throw Error();
}
- let oldAmount = reserve.current_amount;
- let newAmount = reserveInfo.balance;
+ const oldAmount = reserve.current_amount;
+ const newAmount = reserveInfo.balance;
reserve.current_amount = reserveInfo.balance;
- let historyEntry = {
- type: "reserve-update",
- timestamp: (new Date).getTime(),
- subjectId: `reserve-progress-${reserve.reserve_pub}`,
+ const historyEntry = {
detail: {
- reservePub,
- requestedAmount: reserve.requested_amount,
+ newAmount,
oldAmount,
- newAmount
- }
+ requestedAmount: reserve.requested_amount,
+ reservePub,
+ },
+ subjectId: `reserve-progress-${reserve.reserve_pub}`,
+ timestamp: (new Date()).getTime(),
+ type: "reserve-update",
};
await this.q()
.put(Stores.reserves, reserve)
@@ -1272,16 +1288,16 @@ export class Wallet {
*/
async getWireInfo(exchangeBaseUrl: string): Promise<WireInfo> {
exchangeBaseUrl = canonicalizeBaseUrl(exchangeBaseUrl);
- let reqUrl = new URI("wire").absoluteTo(exchangeBaseUrl);
- let resp = await this.http.get(reqUrl.href());
+ const reqUrl = new URI("wire").absoluteTo(exchangeBaseUrl);
+ const resp = await this.http.get(reqUrl.href());
- if (resp.status != 200) {
+ if (resp.status !== 200) {
throw Error("/wire request failed");
}
- let wiJson = JSON.parse(resp.responseText);
+ const wiJson = JSON.parse(resp.responseText);
if (!wiJson) {
- throw Error("/wire response malformed")
+ throw Error("/wire response malformed");
}
return wiJson;
}
@@ -1290,7 +1306,7 @@ export class Wallet {
return (
this.q().iterIndex(Stores.denominations.exchangeBaseUrlIndex,
exchangeBaseUrl)
- .filter((d) => d.status == DenominationStatus.Unverified || d.status == DenominationStatus.VerifiedGood)
+ .filter((d) => d.status === DenominationStatus.Unverified || d.status === DenominationStatus.VerifiedGood)
.toArray()
);
}
@@ -1312,7 +1328,7 @@ export class Wallet {
const possibleDenoms = await (
this.q().iterIndex(Stores.denominations.exchangeBaseUrlIndex,
exchange.baseUrl)
- .filter((d) => d.status == DenominationStatus.Unverified || d.status == DenominationStatus.VerifiedGood)
+ .filter((d) => d.status === DenominationStatus.Unverified || d.status === DenominationStatus.VerifiedGood)
.toArray()
);
@@ -1323,12 +1339,12 @@ export class Wallet {
do {
allValid = true;
- let nextPossibleDenoms = [];
+ const nextPossibleDenoms = [];
selectedDenoms = getWithdrawDenomList(amount, possibleDenoms);
- for (let denom of selectedDenoms || []) {
- if (denom.status == DenominationStatus.Unverified) {
+ for (const denom of selectedDenoms || []) {
+ if (denom.status === DenominationStatus.Unverified) {
console.log(`verifying denom ${denom.denomPub.substr(0, 15)}`);
- let valid = await this.cryptoApi.isValidDenom(denom,
+ const valid = await this.cryptoApi.isValidDenom(denom,
exchange.masterPublicKey);
if (!valid) {
denom.status = DenominationStatus.VerifiedBad;
@@ -1349,24 +1365,23 @@ export class Wallet {
}
-
/**
* Check if and how an exchange is trusted and/or audited.
*/
async getExchangeTrust(exchangeInfo: ExchangeRecord): Promise<{isTrusted: boolean, isAudited: boolean}> {
let isTrusted = false;
let isAudited = false;
- let currencyRecord = await this.q().get(Stores.currencies, exchangeInfo.currency);
+ const currencyRecord = await this.q().get(Stores.currencies, exchangeInfo.currency);
if (currencyRecord) {
- for (let trustedExchange of currencyRecord.exchanges) {
- if (trustedExchange.baseUrl == exchangeInfo.baseUrl) {
+ for (const trustedExchange of currencyRecord.exchanges) {
+ if (trustedExchange.baseUrl === exchangeInfo.baseUrl) {
isTrusted = true;
break;
}
}
- for (let trustedAuditor of currencyRecord.auditors) {
- for (let exchangeAuditor of exchangeInfo.auditors) {
- if (trustedAuditor.baseUrl == exchangeAuditor.url) {
+ for (const trustedAuditor of currencyRecord.auditors) {
+ for (const exchangeAuditor of exchangeInfo.auditors) {
+ if (trustedAuditor.baseUrl === exchangeAuditor.url) {
isAudited = true;
break;
}
@@ -1378,47 +1393,47 @@ export class Wallet {
async getReserveCreationInfo(baseUrl: string,
amount: AmountJson): Promise<ReserveCreationInfo> {
- let exchangeInfo = await this.updateExchangeFromUrl(baseUrl);
+ const exchangeInfo = await this.updateExchangeFromUrl(baseUrl);
- let selectedDenoms = await this.getVerifiedWithdrawDenomList(baseUrl,
+ const selectedDenoms = await this.getVerifiedWithdrawDenomList(baseUrl,
amount);
let acc = Amounts.getZero(amount.currency);
- for (let d of selectedDenoms) {
+ for (const d of selectedDenoms) {
acc = Amounts.add(acc, d.feeWithdraw).amount;
}
- let actualCoinCost = selectedDenoms
+ const actualCoinCost = selectedDenoms
.map((d: DenominationRecord) => Amounts.add(d.value,
d.feeWithdraw).amount)
.reduce((a, b) => Amounts.add(a, b).amount);
- let wireInfo = await this.getWireInfo(baseUrl);
+ const wireInfo = await this.getWireInfo(baseUrl);
- let wireFees = await this.q().get(Stores.exchangeWireFees, baseUrl);
+ const wireFees = await this.q().get(Stores.exchangeWireFees, baseUrl);
if (!wireFees) {
// should never happen unless DB is inconsistent
throw Error(`no wire fees found for exchange ${baseUrl}`);
}
- let {isTrusted, isAudited} = await this.getExchangeTrust(exchangeInfo);
+ const {isTrusted, isAudited} = await this.getExchangeTrust(exchangeInfo);
- let earliestDepositExpiration = Infinity;;
- for (let denom of selectedDenoms) {
- let expireDeposit = getTalerStampSec(denom.stampExpireDeposit)!;
+ let earliestDepositExpiration = Infinity;
+ for (const denom of selectedDenoms) {
+ const expireDeposit = getTalerStampSec(denom.stampExpireDeposit)!;
if (expireDeposit < earliestDepositExpiration) {
earliestDepositExpiration = expireDeposit;
}
}
- let ret: ReserveCreationInfo = {
+ const ret: ReserveCreationInfo = {
+ earliestDepositExpiration,
exchangeInfo,
- selectedDenoms,
- wireInfo,
- wireFees,
isAudited,
isTrusted,
- withdrawFee: acc,
- earliestDepositExpiration,
overhead: Amounts.sub(amount, actualCoinCost).amount,
+ selectedDenoms,
+ wireFees,
+ wireInfo,
+ withdrawFee: acc,
};
return ret;
}
@@ -1431,24 +1446,24 @@ export class Wallet {
*/
async updateExchangeFromUrl(baseUrl: string): Promise<ExchangeRecord> {
baseUrl = canonicalizeBaseUrl(baseUrl);
- let keysUrl = new URI("keys").absoluteTo(baseUrl);
- let wireUrl = new URI("wire").absoluteTo(baseUrl);
- let keysResp = await this.http.get(keysUrl.href());
- if (keysResp.status != 200) {
+ const keysUrl = new URI("keys").absoluteTo(baseUrl);
+ const wireUrl = new URI("wire").absoluteTo(baseUrl);
+ const keysResp = await this.http.get(keysUrl.href());
+ if (keysResp.status !== 200) {
throw Error("/keys request failed");
}
- let wireResp = await this.http.get(wireUrl.href());
- if (wireResp.status != 200) {
+ const wireResp = await this.http.get(wireUrl.href());
+ if (wireResp.status !== 200) {
throw Error("/wire request failed");
}
- let exchangeKeysJson = KeysJson.checked(JSON.parse(keysResp.responseText));
- let wireRespJson = JSON.parse(wireResp.responseText);
+ const exchangeKeysJson = KeysJson.checked(JSON.parse(keysResp.responseText));
+ const wireRespJson = JSON.parse(wireResp.responseText);
if (typeof wireRespJson !== "object") {
throw Error("/wire response is not an object");
}
console.log("exchange wire", wireRespJson);
- let wireMethodDetails: WireDetailJson[] = [];
- for (let methodName in wireRespJson) {
+ const wireMethodDetails: WireDetailJson[] = [];
+ for (const methodName in wireRespJson) {
wireMethodDetails.push(WireDetailJson.checked(wireRespJson[methodName]));
}
return this.updateExchangeFromJson(baseUrl, exchangeKeysJson, wireMethodDetails);
@@ -1456,12 +1471,12 @@ export class Wallet {
private async suspendCoins(exchangeInfo: ExchangeRecord): Promise<void> {
- let suspendedCoins = await (
+ const resultSuspendedCoins = await (
this.q()
.iterIndex(Stores.coins.exchangeBaseUrlIndex, exchangeInfo.baseUrl)
.indexJoinLeft(Stores.denominations.exchangeBaseUrlIndex,
(e) => e.exchangeBaseUrl)
- .reduce((cd: JoinLeftResult<CoinRecord,DenominationRecord>,
+ .reduce((cd: JoinLeftResult<CoinRecord, DenominationRecord>,
suspendedCoins: CoinRecord[]) => {
if ((!cd.right) || (!cd.right.isOffered)) {
return Array.prototype.concat(suspendedCoins, [cd.left]);
@@ -1469,8 +1484,8 @@ export class Wallet {
return Array.prototype.concat(suspendedCoins);
}, []));
- let q = this.q();
- suspendedCoins.map((c) => {
+ const q = this.q();
+ resultSuspendedCoins.map((c) => {
console.log("suspending coin", c);
c.suspended = true;
q.put(Stores.coins, c);
@@ -1489,7 +1504,7 @@ export class Wallet {
throw Error("invalid update time");
}
- if (exchangeKeysJson.denoms.length == 0) {
+ if (exchangeKeysJson.denoms.length === 0) {
throw Error("exchange doesn't offer any denominations");
}
@@ -1499,24 +1514,24 @@ export class Wallet {
if (!r) {
exchangeInfo = {
+ auditors: exchangeKeysJson.auditors,
baseUrl,
+ currency: exchangeKeysJson.denoms[0].value.currency,
lastUpdateTime: updateTimeSec,
masterPublicKey: exchangeKeysJson.master_public_key,
- auditors: exchangeKeysJson.auditors,
- currency: exchangeKeysJson.denoms[0].value.currency,
};
console.log("making fresh exchange");
} else {
if (updateTimeSec < r.lastUpdateTime) {
console.log("outdated /keys, not updating");
- return r
+ return r;
}
exchangeInfo = r;
exchangeInfo.lastUpdateTime = updateTimeSec;
console.log("updating old exchange");
}
- let updatedExchangeInfo = await this.updateExchangeInfo(exchangeInfo,
+ const updatedExchangeInfo = await this.updateExchangeInfo(exchangeInfo,
exchangeKeysJson);
await this.suspendCoins(updatedExchangeInfo);
@@ -1532,37 +1547,37 @@ export class Wallet {
};
}
- for (let detail of wireMethodDetails) {
+ for (const detail of wireMethodDetails) {
let latestFeeStamp = 0;
- let fees = oldWireFees.feesForType[detail.type] || [];
+ const fees = oldWireFees.feesForType[detail.type] || [];
oldWireFees.feesForType[detail.type] = fees;
- for (let oldFee of fees) {
+ for (const oldFee of fees) {
if (oldFee.endStamp > latestFeeStamp) {
latestFeeStamp = oldFee.endStamp;
}
}
- for (let fee of detail.fees) {
- let start = getTalerStampSec(fee.start_date);
- if (start == null) {
+ for (const fee of detail.fees) {
+ const start = getTalerStampSec(fee.start_date);
+ if (start === null) {
console.error("invalid start stamp in fee", fee);
continue;
}
if (start < latestFeeStamp) {
continue;
}
- let end = getTalerStampSec(fee.end_date);
- if (end == null) {
+ const end = getTalerStampSec(fee.end_date);
+ if (end === null) {
console.error("invalid end stamp in fee", fee);
continue;
}
- let wf: WireFee = {
- wireFee: fee.wire_fee,
+ const wf: WireFee = {
closingFee: fee.closing_fee,
+ endStamp: end,
sig: fee.sig,
startStamp: start,
- endStamp: end,
- }
- let valid: boolean = await this.cryptoApi.isValidWireFee(detail.type, wf, exchangeInfo.masterPublicKey);
+ wireFee: fee.wire_fee,
+ };
+ const valid: boolean = await this.cryptoApi.isValidWireFee(detail.type, wf, exchangeInfo.masterPublicKey);
if (!valid) {
console.error("fee signature invalid", fee);
throw Error("fee signature invalid");
@@ -1574,14 +1589,14 @@ export class Wallet {
await this.q().put(Stores.exchangeWireFees, oldWireFees);
if (exchangeKeysJson.payback) {
- for (let payback of exchangeKeysJson.payback) {
- let denom = await this.q().getIndexed(Stores.denominations.denomPubHashIndex, payback.h_denom_pub);
+ for (const payback of exchangeKeysJson.payback) {
+ const denom = await this.q().getIndexed(Stores.denominations.denomPubHashIndex, payback.h_denom_pub);
if (!denom) {
continue;
}
console.log(`cashing back denom`, denom);
- let coins = await this.q().iterIndex(Stores.coins.denomPubIndex, denom.denomPub).toArray();
- for (let coin of coins) {
+ const coins = await this.q().iterIndex(Stores.coins.denomPubIndex, denom.denomPub).toArray();
+ for (const coin of coins) {
this.payback(coin.coinPub);
}
}
@@ -1593,7 +1608,7 @@ export class Wallet {
private async updateExchangeInfo(exchangeInfo: ExchangeRecord,
newKeys: KeysJson): Promise<ExchangeRecord> {
- if (exchangeInfo.masterPublicKey != newKeys.master_public_key) {
+ if (exchangeInfo.masterPublicKey !== newKeys.master_public_key) {
throw Error("public keys do not match");
}
@@ -1608,17 +1623,17 @@ export class Wallet {
const newDenoms: typeof existingDenoms = {};
const newAndUnseenDenoms: typeof existingDenoms = {};
- for (let d of newKeys.denoms) {
- let dr = await this.denominationRecordFromKeys(exchangeInfo.baseUrl, d);
+ for (const d of newKeys.denoms) {
+ const dr = await this.denominationRecordFromKeys(exchangeInfo.baseUrl, d);
if (!(d.denom_pub in existingDenoms)) {
newAndUnseenDenoms[dr.denomPub] = dr;
}
newDenoms[dr.denomPub] = dr;
}
- for (let oldDenomPub in existingDenoms) {
+ for (const oldDenomPub in existingDenoms) {
if (!(oldDenomPub in newDenoms)) {
- let d = existingDenoms[oldDenomPub];
+ const d = existingDenoms[oldDenomPub];
d.isOffered = false;
}
}
@@ -1640,13 +1655,13 @@ export class Wallet {
async getBalances(): Promise<WalletBalance> {
function ensureEntry(balance: WalletBalance, currency: string) {
let entry: WalletBalanceEntry|undefined = balance[currency];
- let z = Amounts.getZero(currency);
+ const z = Amounts.getZero(currency);
if (!entry) {
balance[currency] = entry = {
available: z,
+ paybackAmount: z,
pendingIncoming: z,
pendingPayment: z,
- paybackAmount: z,
};
}
return entry;
@@ -1656,11 +1671,11 @@ export class Wallet {
if (c.suspended) {
return balance;
}
- if (!(c.status == CoinStatus.Dirty || c.status == CoinStatus.Fresh)) {
+ if (!(c.status === CoinStatus.Dirty || c.status === CoinStatus.Fresh)) {
return balance;
}
- let currency = c.currentAmount.currency;
- let entry = ensureEntry(balance, currency);
+ const currency = c.currentAmount.currency;
+ const entry = ensureEntry(balance, currency);
entry.available = Amounts.add(entry.available, c.currentAmount).amount;
return balance;
}
@@ -1669,7 +1684,7 @@ export class Wallet {
if (!r.confirmed) {
return balance;
}
- let entry = ensureEntry(balance, r.requested_amount.currency);
+ const entry = ensureEntry(balance, r.requested_amount.currency);
let amount = r.current_amount;
if (!amount) {
amount = r.requested_amount;
@@ -1686,7 +1701,7 @@ export class Wallet {
if (!r.hasPayback) {
return balance;
}
- let entry = ensureEntry(balance, r.requested_amount.currency);
+ const entry = ensureEntry(balance, r.requested_amount.currency);
if (Amounts.cmp(smallestWithdraw[r.exchange_base_url], r.current_amount!) < 0) {
entry.paybackAmount = Amounts.add(entry.paybackAmount, r.current_amount!).amount;
}
@@ -1700,7 +1715,7 @@ export class Wallet {
if (r.finished) {
return balance;
}
- let entry = ensureEntry(balance, r.valueWithFee.currency);
+ const entry = ensureEntry(balance, r.valueWithFee.currency);
entry.pendingIncoming = Amounts.add(entry.pendingIncoming,
r.valueOutput).amount;
@@ -1711,7 +1726,7 @@ export class Wallet {
if (t.finished) {
return balance;
}
- let entry = ensureEntry(balance, t.contract.amount.currency);
+ const entry = ensureEntry(balance, t.contract.amount.currency);
entry.pendingPayment = Amounts.add(entry.pendingPayment,
t.contract.amount).amount;
@@ -1721,7 +1736,7 @@ export class Wallet {
function collectSmallestWithdraw(e: JoinResult<ExchangeRecord, DenominationRecord>,
sw: any) {
let min = sw[e.left.baseUrl];
- let v = Amounts.add(e.right.value, e.right.feeWithdraw).amount;
+ const v = Amounts.add(e.right.value, e.right.feeWithdraw).amount;
if (!min) {
min = v;
} else if (Amounts.cmp(v, min) < 0) {
@@ -1731,7 +1746,7 @@ export class Wallet {
return sw;
}
- let balance = {};
+ const balance = {};
// Mapping from exchange pub to smallest
// possible amount we can withdraw
let smallestWithdraw: {[baseUrl: string]: AmountJson} = {};
@@ -1742,7 +1757,7 @@ export class Wallet {
(x) => x.baseUrl)
.reduce(collectSmallestWithdraw, {}));
- let tx = this.q();
+ const tx = this.q();
tx.iter(Stores.coins)
.reduce(collectBalances, balance);
tx.iter(Stores.refresh)
@@ -1760,52 +1775,52 @@ export class Wallet {
async createRefreshSession(oldCoinPub: string): Promise<RefreshSessionRecord|undefined> {
- let coin = await this.q().get<CoinRecord>(Stores.coins, oldCoinPub);
+ const coin = await this.q().get<CoinRecord>(Stores.coins, oldCoinPub);
if (!coin) {
throw Error("coin not found");
}
- if (coin.currentAmount.value == 0 && coin.currentAmount.fraction == 0) {
+ if (coin.currentAmount.value === 0 && coin.currentAmount.fraction === 0) {
return undefined;
}
- let exchange = await this.updateExchangeFromUrl(coin.exchangeBaseUrl);
+ const exchange = await this.updateExchangeFromUrl(coin.exchangeBaseUrl);
if (!exchange) {
throw Error("db inconsistent");
}
- let oldDenom = await this.q().get(Stores.denominations,
+ const oldDenom = await this.q().get(Stores.denominations,
[exchange.baseUrl, coin.denomPub]);
if (!oldDenom) {
throw Error("db inconsistent");
}
- let availableDenoms: DenominationRecord[] = await (
+ const availableDenoms: DenominationRecord[] = await (
this.q()
.iterIndex(Stores.denominations.exchangeBaseUrlIndex,
exchange.baseUrl)
.toArray()
);
- let availableAmount = Amounts.sub(coin.currentAmount,
+ const availableAmount = Amounts.sub(coin.currentAmount,
oldDenom.feeRefresh).amount;
- let newCoinDenoms = getWithdrawDenomList(availableAmount,
+ const newCoinDenoms = getWithdrawDenomList(availableAmount,
availableDenoms);
console.log("refreshing coin", coin);
console.log("refreshing into", newCoinDenoms);
- if (newCoinDenoms.length == 0) {
+ if (newCoinDenoms.length === 0) {
console.log(`not refreshing, available amount ${amountToPretty(availableAmount)} too small`);
return undefined;
}
- let refreshSession: RefreshSessionRecord = await (
+ const refreshSession: RefreshSessionRecord = await (
this.cryptoApi.createRefreshSession(exchange.baseUrl,
3,
coin,
@@ -1813,7 +1828,7 @@ export class Wallet {
oldDenom.feeRefresh));
function mutateCoin(c: CoinRecord): CoinRecord {
- let r = Amounts.sub(c.currentAmount,
+ const r = Amounts.sub(c.currentAmount,
refreshSession.valueWithFee);
if (r.saturated) {
// Something else must have written the coin value
@@ -1837,7 +1852,7 @@ export class Wallet {
async refresh(oldCoinPub: string): Promise<void> {
let refreshSession: RefreshSessionRecord|undefined;
- let oldSession = await this.q().get(Stores.refresh, oldCoinPub);
+ const oldSession = await this.q().get(Stores.refresh, oldCoinPub);
if (oldSession) {
console.log("got old session for", oldCoinPub);
console.log(oldSession);
@@ -1858,9 +1873,9 @@ export class Wallet {
return;
}
if (typeof refreshSession.norevealIndex !== "number") {
- let coinPub = refreshSession.meltCoinPub;
+ const coinPub = refreshSession.meltCoinPub;
await this.refreshMelt(refreshSession);
- let r = await this.q().get<RefreshSessionRecord>(Stores.refresh, coinPub);
+ const r = await this.q().get<RefreshSessionRecord>(Stores.refresh, coinPub);
if (!r) {
throw Error("refresh session does not exist anymore");
}
@@ -1872,53 +1887,53 @@ export class Wallet {
async refreshMelt(refreshSession: RefreshSessionRecord): Promise<void> {
- if (refreshSession.norevealIndex != undefined) {
+ if (refreshSession.norevealIndex !== undefined) {
console.error("won't melt again");
return;
}
- let coin = await this.q().get<CoinRecord>(Stores.coins,
+ const coin = await this.q().get<CoinRecord>(Stores.coins,
refreshSession.meltCoinPub);
if (!coin) {
console.error("can't melt coin, it does not exist");
return;
}
- let reqUrl = new URI("refresh/melt").absoluteTo(refreshSession.exchangeBaseUrl);
- let meltCoin = {
+ const reqUrl = new URI("refresh/melt").absoluteTo(refreshSession.exchangeBaseUrl);
+ const meltCoin = {
coin_pub: coin.coinPub,
+ confirm_sig: refreshSession.confirmSig,
denom_pub: coin.denomPub,
denom_sig: coin.denomSig,
- confirm_sig: refreshSession.confirmSig,
value_with_fee: refreshSession.valueWithFee,
};
- let coinEvs = refreshSession.preCoinsForGammas.map((x) => x.map((y) => y.coinEv));
- let req = {
- "new_denoms": refreshSession.newDenoms,
- "melt_coin": meltCoin,
- "transfer_pubs": refreshSession.transferPubs,
- "coin_evs": coinEvs,
+ const coinEvs = refreshSession.preCoinsForGammas.map((x) => x.map((y) => y.coinEv));
+ const req = {
+ coin_evs: coinEvs,
+ melt_coin: meltCoin,
+ new_denoms: refreshSession.newDenoms,
+ transfer_pubs: refreshSession.transferPubs,
};
console.log("melt request:", req);
- let resp = await this.http.postJson(reqUrl.href(), req);
+ const resp = await this.http.postJson(reqUrl.href(), req);
console.log("melt request:", req);
console.log("melt response:", resp.responseText);
- if (resp.status != 200) {
+ if (resp.status !== 200) {
console.error(resp.responseText);
throw Error("refresh failed");
}
- let respJson = JSON.parse(resp.responseText);
+ const respJson = JSON.parse(resp.responseText);
if (!respJson) {
throw Error("exchange responded with garbage");
}
- let norevealIndex = respJson.noreveal_index;
+ const norevealIndex = respJson.noreveal_index;
- if (typeof norevealIndex != "number") {
+ if (typeof norevealIndex !== "number") {
throw Error("invalid response");
}
@@ -1929,71 +1944,70 @@ export class Wallet {
async refreshReveal(refreshSession: RefreshSessionRecord): Promise<void> {
- let norevealIndex = refreshSession.norevealIndex;
- if (norevealIndex == undefined) {
+ const norevealIndex = refreshSession.norevealIndex;
+ if (norevealIndex === undefined) {
throw Error("can't reveal without melting first");
}
- let privs = Array.from(refreshSession.transferPrivs);
+ const privs = Array.from(refreshSession.transferPrivs);
privs.splice(norevealIndex, 1);
- let req = {
- "session_hash": refreshSession.hash,
- "transfer_privs": privs,
+ const req = {
+ session_hash: refreshSession.hash,
+ transfer_privs: privs,
};
- let reqUrl = new URI("refresh/reveal")
- .absoluteTo(refreshSession.exchangeBaseUrl);
+ const reqUrl = new URI("refresh/reveal") .absoluteTo(refreshSession.exchangeBaseUrl);
console.log("reveal request:", req);
- let resp = await this.http.postJson(reqUrl.href(), req);
+ const resp = await this.http.postJson(reqUrl.href(), req);
console.log("session:", refreshSession);
console.log("reveal response:", resp);
- if (resp.status != 200) {
+ if (resp.status !== 200) {
console.log("error: /refresh/reveal returned status " + resp.status);
return;
}
- let respJson = JSON.parse(resp.responseText);
+ const respJson = JSON.parse(resp.responseText);
if (!respJson.ev_sigs || !Array.isArray(respJson.ev_sigs)) {
console.log("/refresh/reveal did not contain ev_sigs");
}
- let exchange = await this.q().get<ExchangeRecord>(Stores.exchanges,
+ const exchange = await this.q().get<ExchangeRecord>(Stores.exchanges,
refreshSession.exchangeBaseUrl);
if (!exchange) {
console.error(`exchange ${refreshSession.exchangeBaseUrl} not found`);
return;
}
- let coins: CoinRecord[] = [];
+ const coins: CoinRecord[] = [];
for (let i = 0; i < respJson.ev_sigs.length; i++) {
- let denom = await (
+ const denom = await (
this.q()
.get(Stores.denominations,
[
refreshSession.exchangeBaseUrl,
- refreshSession.newDenoms[i]
+ refreshSession.newDenoms[i],
]));
if (!denom) {
console.error("denom not found");
continue;
}
- let pc = refreshSession.preCoinsForGammas[refreshSession.norevealIndex!][i];
- let denomSig = await this.cryptoApi.rsaUnblind(respJson.ev_sigs[i].ev_sig,
+ const pc = refreshSession.preCoinsForGammas[refreshSession.norevealIndex!][i];
+ const denomSig = await this.cryptoApi.rsaUnblind(respJson.ev_sigs[i].ev_sig,
pc.blindingKey,
denom.denomPub);
- let coin: CoinRecord = {
- reservePub: undefined,
+ const coin: CoinRecord = {
blindingKey: pc.blindingKey,
- coinPub: pc.publicKey,
coinPriv: pc.privateKey,
- denomPub: denom.denomPub,
- denomSig: denomSig,
+ coinPub: pc.publicKey,
currentAmount: denom.value,
+ denomPub: denom.denomPub,
+ denomSig,
exchangeBaseUrl: refreshSession.exchangeBaseUrl,
+ reservePub: undefined,
status: CoinStatus.Fresh,
};
@@ -2018,7 +2032,7 @@ export class Wallet {
return acc;
}
- let history = await (
+ const history = await (
this.q()
.iterIndex(Stores.history.timestampIndex)
.reduce(collect, []));
@@ -2027,12 +2041,12 @@ export class Wallet {
}
async getDenoms(exchangeUrl: string): Promise<DenominationRecord[]> {
- let denoms = await this.q().iterIndex(Stores.denominations.exchangeBaseUrlIndex, exchangeUrl).toArray();
+ const denoms = await this.q().iterIndex(Stores.denominations.exchangeBaseUrlIndex, exchangeUrl).toArray();
return denoms;
}
async getOffer(offerId: number): Promise<any> {
- let offer = await this.q() .get(Stores.offers, offerId);
+ const offer = await this.q() .get(Stores.offers, offerId);
return offer;
}
@@ -2089,7 +2103,7 @@ export class Wallet {
* Store the private key in our DB, so we can prove ownership.
*/
async generateNonce(): Promise<string> {
- let {priv, pub} = await this.cryptoApi.createEddsaKeypair();
+ const {priv, pub} = await this.cryptoApi.createEddsaKeypair();
await this.q()
.put(Stores.nonces, {priv, pub})
.finish();
@@ -2103,23 +2117,23 @@ export class Wallet {
async paymentSucceeded(contractHash: string, merchantSig: string): Promise<any> {
const doPaymentSucceeded = async() => {
- let t = await this.q().get<TransactionRecord>(Stores.transactions,
+ const t = await this.q().get<TransactionRecord>(Stores.transactions,
contractHash);
if (!t) {
console.error("contract not found");
return;
}
- let merchantPub = t.contract.merchant_pub;
- let valid = this.cryptoApi.isValidPaymentSignature(merchantSig, contractHash, merchantPub);
+ const merchantPub = t.contract.merchant_pub;
+ const valid = this.cryptoApi.isValidPaymentSignature(merchantSig, contractHash, merchantPub);
if (!valid) {
console.error("merchant payment signature invalid");
// FIXME: properly display error
return;
}
t.finished = true;
- let modifiedCoins: CoinRecord[] = [];
- for (let pc of t.payReq.coins) {
- let c = await this.q().get<CoinRecord>(Stores.coins, pc.coin_pub);
+ const modifiedCoins: CoinRecord[] = [];
+ for (const pc of t.payReq.coins) {
+ const c = await this.q().get<CoinRecord>(Stores.coins, pc.coin_pub);
if (!c) {
console.error("coin not found");
return;
@@ -2132,7 +2146,7 @@ export class Wallet {
.putAll(Stores.coins, modifiedCoins)
.put(Stores.transactions, t)
.finish();
- for (let c of t.payReq.coins) {
+ for (const c of t.payReq.coins) {
this.refresh(c.coin_pub);
}
};
@@ -2145,11 +2159,11 @@ export class Wallet {
if (!coin) {
throw Error(`Coin ${coinPub} not found, can't request payback`);
}
- let reservePub = coin.reservePub;
+ const reservePub = coin.reservePub;
if (!reservePub) {
throw Error(`Can't request payback for a refreshed coin`);
}
- let reserve = await this.q().get(Stores.reserves, reservePub);
+ const reserve = await this.q().get(Stores.reserves, reservePub);
if (!reserve) {
throw Error(`Reserve of coin ${coinPub} not found`);
}
@@ -2167,14 +2181,14 @@ export class Wallet {
reserve.hasPayback = true;
await this.q().put(Stores.coins, coin).put(Stores.reserves, reserve);
- let paybackRequest = await this.cryptoApi.createPaybackRequest(coin);
- let reqUrl = new URI("payback").absoluteTo(coin.exchangeBaseUrl);
- let resp = await this.http.postJson(reqUrl.href(), paybackRequest);
- if (resp.status != 200) {
+ const paybackRequest = await this.cryptoApi.createPaybackRequest(coin);
+ const reqUrl = new URI("payback").absoluteTo(coin.exchangeBaseUrl);
+ const resp = await this.http.postJson(reqUrl.href(), paybackRequest);
+ if (resp.status !== 200) {
throw Error();
}
- let paybackConfirmation = PaybackConfirmation.checked(JSON.parse(resp.responseText));
- if (paybackConfirmation.reserve_pub != coin.reservePub) {
+ const paybackConfirmation = PaybackConfirmation.checked(JSON.parse(resp.responseText));
+ if (paybackConfirmation.reserve_pub !== coin.reservePub) {
throw Error(`Coin's reserve doesn't match reserve on payback`);
}
coin = await this.q().get(Stores.coins, coinPub);
@@ -2188,29 +2202,29 @@ export class Wallet {
async denominationRecordFromKeys(exchangeBaseUrl: string, denomIn: Denomination): Promise<DenominationRecord> {
- let denomPubHash = await this.cryptoApi.hashDenomPub(denomIn.denom_pub);
- let d: DenominationRecord = {
- denomPubHash,
+ const denomPubHash = await this.cryptoApi.hashDenomPub(denomIn.denom_pub);
+ const d: DenominationRecord = {
denomPub: denomIn.denom_pub,
- exchangeBaseUrl: exchangeBaseUrl,
+ denomPubHash,
+ exchangeBaseUrl,
feeDeposit: denomIn.fee_deposit,
- masterSig: denomIn.master_sig,
- feeRefund: denomIn.fee_refund,
feeRefresh: denomIn.fee_refresh,
+ feeRefund: denomIn.fee_refund,
feeWithdraw: denomIn.fee_withdraw,
+ isOffered: true,
+ masterSig: denomIn.master_sig,
stampExpireDeposit: denomIn.stamp_expire_deposit,
stampExpireLegal: denomIn.stamp_expire_legal,
stampExpireWithdraw: denomIn.stamp_expire_withdraw,
stampStart: denomIn.stamp_start,
status: DenominationStatus.Unverified,
- isOffered: true,
value: denomIn.value,
};
return d;
}
async withdrawPaybackReserve(reservePub: string): Promise<void> {
- let reserve = await this.q().get(Stores.reserves, reservePub);
+ const reserve = await this.q().get(Stores.reserves, reservePub);
if (!reserve) {
throw Error(`Reserve ${reservePub} does not exist`);
}
@@ -2220,7 +2234,7 @@ export class Wallet {
}
async getPaybackReserves(): Promise<ReserveRecord[]> {
- return await this.q().iter(Stores.reserves).filter(r => r.hasPayback).toArray()
+ return await this.q().iter(Stores.reserves).filter((r) => r.hasPayback).toArray();
}
}
diff --git a/src/wxApi.ts b/src/wxApi.ts
index b74cb9eb1..1f7d08fb3 100644
--- a/src/wxApi.ts
+++ b/src/wxApi.ts
@@ -17,11 +17,12 @@
import {
AmountJson,
CoinRecord,
+ CurrencyRecord,
+ DenominationRecord,
+ ExchangeRecord,
PreCoinRecord,
ReserveCreationInfo,
- ExchangeRecord,
- CurrencyRecord,
- ReserveRecord, DenominationRecord
+ ReserveRecord,
} from "./types";
/**
@@ -31,13 +32,13 @@ import {
export function getReserveCreationInfo(baseUrl: string,
- amount: AmountJson): Promise<ReserveCreationInfo> {
- let m = { type: "reserve-creation-info", detail: { baseUrl, amount } };
+ amount: AmountJson): Promise<ReserveCreationInfo> {
+ const m = { type: "reserve-creation-info", detail: { baseUrl, amount } };
return new Promise<ReserveCreationInfo>((resolve, reject) => {
chrome.runtime.sendMessage(m, (resp) => {
if (resp.error) {
console.error("error response", resp);
- let e = Error("call to reserve-creation-info failed");
+ const e = Error("call to reserve-creation-info failed");
(e as any).errorResponse = resp;
reject(e);
return;
diff --git a/src/wxBackend.ts b/src/wxBackend.ts
index 26020c7fe..6b9601572 100644
--- a/src/wxBackend.ts
+++ b/src/wxBackend.ts
@@ -24,6 +24,20 @@
/**
* Imports.
*/
+import { Checkable } from "./checkable";
+import { ChromeBadge } from "./chromeBadge";
+import { BrowserHttpLib } from "./http";
+import * as logging from "./logging";
+import {
+ Index,
+ Store,
+} from "./query";
+import {
+ AmountJson,
+ Contract,
+ Notifier,
+} from "./types";
+import URI = require("urijs");
import {
Badge,
ConfirmReserveRequest,
@@ -32,19 +46,8 @@ import {
Stores,
Wallet,
} from "./wallet";
-import {
- AmountJson,
- Contract,
- Notifier,
-} from "./types";
-import MessageSender = chrome.runtime.MessageSender;
-import { ChromeBadge } from "./chromeBadge";
-import * as logging from "./logging";
-import { Store, Index } from "./query";
-import { BrowserHttpLib } from "./http";
-import { Checkable } from "./checkable";
import Port = chrome.runtime.Port;
-import URI = require("urijs");
+import MessageSender = chrome.runtime.MessageSender;
const DB_NAME = "taler";
@@ -60,32 +63,33 @@ const DB_VERSION = 17;
type Handler = (detail: any, sender: MessageSender) => Promise<any>;
function makeHandlers(db: IDBDatabase,
- wallet: Wallet): { [msg: string]: Handler } {
+ wallet: Wallet): { [msg: string]: Handler } {
return {
- ["balances"]: function (detail, sender) {
+ ["balances"]: (detail, sender) => {
return wallet.getBalances();
},
- ["dump-db"]: function (detail, sender) {
+ ["dump-db"]: (detail, sender) => {
return exportDb(db);
},
- ["import-db"]: function (detail, sender) {
+ ["import-db"]: (detail, sender) => {
return importDb(db, detail.dump);
},
- ["get-tab-cookie"]: function (detail, sender) {
+ ["get-tab-cookie"]: (detail, sender) => {
if (!sender || !sender.tab || !sender.tab.id) {
return Promise.resolve();
}
- let id: number = sender.tab.id;
- let info: any = <any> paymentRequestCookies[id];
+ const id: number = sender.tab.id;
+ const info: any = paymentRequestCookies[id] as any;
delete paymentRequestCookies[id];
return Promise.resolve(info);
},
- ["ping"]: function (detail, sender) {
+ ["ping"]: (detail, sender) => {
return Promise.resolve();
},
- ["reset"]: function (detail, sender) {
+ ["reset"]: (detail, sender) => {
if (db) {
- let tx = db.transaction(Array.from(db.objectStoreNames), 'readwrite');
+ const tx = db.transaction(Array.from(db.objectStoreNames), "readwrite");
+ // tslint:disable-next-line:prefer-for-of
for (let i = 0; i < db.objectStoreNames.length; i++) {
tx.objectStore(db.objectStoreNames[i]).clear();
}
@@ -97,15 +101,15 @@ function makeHandlers(db: IDBDatabase,
// Response is synchronous
return Promise.resolve({});
},
- ["create-reserve"]: function (detail, sender) {
+ ["create-reserve"]: (detail, sender) => {
const d = {
- exchange: detail.exchange,
amount: detail.amount,
+ exchange: detail.exchange,
};
const req = CreateReserveRequest.checked(d);
return wallet.createReserve(req);
},
- ["confirm-reserve"]: function (detail, sender) {
+ ["confirm-reserve"]: (detail, sender) => {
// TODO: make it a checkable
const d = {
reservePub: detail.reservePub,
@@ -113,10 +117,10 @@ function makeHandlers(db: IDBDatabase,
const req = ConfirmReserveRequest.checked(d);
return wallet.confirmReserve(req);
},
- ["generate-nonce"]: function (detail, sender) {
+ ["generate-nonce"]: (detail, sender) => {
return wallet.generateNonce();
},
- ["confirm-pay"]: function (detail, sender) {
+ ["confirm-pay"]: (detail, sender) => {
let offer: OfferRecord;
try {
offer = OfferRecord.checked(detail.offer);
@@ -124,9 +128,9 @@ function makeHandlers(db: IDBDatabase,
if (e instanceof Checkable.SchemaError) {
console.error("schema error:", e.message);
return Promise.resolve({
+ detail,
error: "invalid contract",
hint: e.message,
- detail: detail,
});
} else {
throw e;
@@ -135,7 +139,7 @@ function makeHandlers(db: IDBDatabase,
return wallet.confirmPay(offer);
},
- ["check-pay"]: function (detail, sender) {
+ ["check-pay"]: (detail, sender) => {
let offer: OfferRecord;
try {
offer = OfferRecord.checked(detail.offer);
@@ -143,9 +147,9 @@ function makeHandlers(db: IDBDatabase,
if (e instanceof Checkable.SchemaError) {
console.error("schema error:", e.message);
return Promise.resolve({
+ detail,
error: "invalid contract",
hint: e.message,
- detail: detail,
});
} else {
throw e;
@@ -153,34 +157,34 @@ function makeHandlers(db: IDBDatabase,
}
return wallet.checkPay(offer);
},
- ["query-payment"]: function (detail: any, sender: MessageSender) {
+ ["query-payment"]: (detail: any, sender: MessageSender) => {
if (sender.tab && sender.tab.id) {
rateLimitCache[sender.tab.id]++;
if (rateLimitCache[sender.tab.id] > 10) {
console.warn("rate limit for query-payment exceeded");
- let msg = {
+ const msg = {
error: "rate limit exceeded for query-payment",
- rateLimitExceeded: true,
hint: "Check for redirect loops",
+ rateLimitExceeded: true,
};
return Promise.resolve(msg);
}
}
return wallet.queryPayment(detail.url);
},
- ["exchange-info"]: function (detail) {
+ ["exchange-info"]: (detail) => {
if (!detail.baseUrl) {
return Promise.resolve({ error: "bad url" });
}
return wallet.updateExchangeFromUrl(detail.baseUrl);
},
- ["currency-info"]: function (detail) {
+ ["currency-info"]: (detail) => {
if (!detail.name) {
return Promise.resolve({ error: "name missing" });
}
return wallet.getCurrencyRecord(detail.name);
},
- ["hash-contract"]: function (detail) {
+ ["hash-contract"]: (detail) => {
if (!detail.contract) {
return Promise.resolve({ error: "contract missing" });
}
@@ -188,91 +192,91 @@ function makeHandlers(db: IDBDatabase,
return { hash };
});
},
- ["put-history-entry"]: function (detail: any) {
+ ["put-history-entry"]: (detail: any) => {
if (!detail.historyEntry) {
return Promise.resolve({ error: "historyEntry missing" });
}
return wallet.putHistory(detail.historyEntry);
},
- ["save-offer"]: function (detail: any) {
- let offer = detail.offer;
+ ["save-offer"]: (detail: any) => {
+ const offer = detail.offer;
if (!offer) {
return Promise.resolve({ error: "offer missing" });
}
console.log("handling safe-offer", detail);
// FIXME: fully migrate to new terminology
- let checkedOffer = OfferRecord.checked(offer);
+ const checkedOffer = OfferRecord.checked(offer);
return wallet.saveOffer(checkedOffer);
},
- ["reserve-creation-info"]: function (detail, sender) {
+ ["reserve-creation-info"]: (detail, sender) => {
if (!detail.baseUrl || typeof detail.baseUrl !== "string") {
return Promise.resolve({ error: "bad url" });
}
- let amount = AmountJson.checked(detail.amount);
+ const amount = AmountJson.checked(detail.amount);
return wallet.getReserveCreationInfo(detail.baseUrl, amount);
},
- ["get-history"]: function (detail, sender) {
+ ["get-history"]: (detail, sender) => {
// TODO: limit history length
return wallet.getHistory();
},
- ["get-offer"]: function (detail, sender) {
+ ["get-offer"]: (detail, sender) => {
return wallet.getOffer(detail.offerId);
},
- ["get-exchanges"]: function (detail, sender) {
+ ["get-exchanges"]: (detail, sender) => {
return wallet.getExchanges();
},
- ["get-currencies"]: function (detail, sender) {
+ ["get-currencies"]: (detail, sender) => {
return wallet.getCurrencies();
},
- ["update-currency"]: function (detail, sender) {
+ ["update-currency"]: (detail, sender) => {
return wallet.updateCurrency(detail.currencyRecord);
},
- ["get-reserves"]: function (detail, sender) {
+ ["get-reserves"]: (detail, sender) => {
if (typeof detail.exchangeBaseUrl !== "string") {
return Promise.reject(Error("exchangeBaseUrl missing"));
}
return wallet.getReserves(detail.exchangeBaseUrl);
},
- ["get-payback-reserves"]: function (detail, sender) {
+ ["get-payback-reserves"]: (detail, sender) => {
return wallet.getPaybackReserves();
},
- ["withdraw-payback-reserve"]: function (detail, sender) {
+ ["withdraw-payback-reserve"]: (detail, sender) => {
if (typeof detail.reservePub !== "string") {
return Promise.reject(Error("reservePub missing"));
}
return wallet.withdrawPaybackReserve(detail.reservePub);
},
- ["get-coins"]: function (detail, sender) {
+ ["get-coins"]: (detail, sender) => {
if (typeof detail.exchangeBaseUrl !== "string") {
return Promise.reject(Error("exchangBaseUrl missing"));
}
return wallet.getCoins(detail.exchangeBaseUrl);
},
- ["get-precoins"]: function (detail, sender) {
+ ["get-precoins"]: (detail, sender) => {
if (typeof detail.exchangeBaseUrl !== "string") {
return Promise.reject(Error("exchangBaseUrl missing"));
}
return wallet.getPreCoins(detail.exchangeBaseUrl);
},
- ["get-denoms"]: function (detail, sender) {
+ ["get-denoms"]: (detail, sender) => {
if (typeof detail.exchangeBaseUrl !== "string") {
return Promise.reject(Error("exchangBaseUrl missing"));
}
return wallet.getDenoms(detail.exchangeBaseUrl);
},
- ["refresh-coin"]: function (detail, sender) {
+ ["refresh-coin"]: (detail, sender) => {
if (typeof detail.coinPub !== "string") {
return Promise.reject(Error("coinPub missing"));
}
return wallet.refresh(detail.coinPub);
},
- ["payback-coin"]: function (detail, sender) {
+ ["payback-coin"]: (detail, sender) => {
if (typeof detail.coinPub !== "string") {
return Promise.reject(Error("coinPub missing"));
}
return wallet.payback(detail.coinPub);
},
- ["payment-failed"]: function (detail, sender) {
+ ["payment-failed"]: (detail, sender) => {
// For now we just update exchanges (maybe the exchange did something
// wrong and the keys were messed up).
// FIXME: in the future we should look at what actually went wrong.
@@ -280,9 +284,9 @@ function makeHandlers(db: IDBDatabase,
wallet.updateExchanges();
return Promise.resolve();
},
- ["payment-succeeded"]: function (detail, sender) {
- let contractHash = detail.contractHash;
- let merchantSig = detail.merchantSig;
+ ["payment-succeeded"]: (detail, sender) => {
+ const contractHash = detail.contractHash;
+ const merchantSig = detail.merchantSig;
if (!contractHash) {
return Promise.reject(Error("contractHash missing"));
}
@@ -307,7 +311,7 @@ async function dispatch(handlers: any, req: any, sender: any, sendResponse: any)
try {
const p = handlers[req.type](req.detail, sender);
- let r = await p;
+ const r = await p;
try {
sendResponse(r);
} catch (e) {
@@ -317,7 +321,7 @@ async function dispatch(handlers: any, req: any, sender: any, sendResponse: any)
console.log(`exception during wallet handler for '${req.type}'`);
console.log("request", req);
console.error(e);
- let stack = undefined;
+ let stack;
try {
stack = e.stack.toString();
} catch (e) {
@@ -325,9 +329,9 @@ async function dispatch(handlers: any, req: any, sender: any, sendResponse: any)
}
try {
sendResponse({
- stack,
error: "exception",
hint: e.message,
+ stack,
});
} catch (e) {
console.log(e);
@@ -344,7 +348,7 @@ class ChromeNotifier implements Notifier {
console.log("got connect!");
this.ports.push(port);
port.onDisconnect.addListener(() => {
- let i = this.ports.indexOf(port);
+ const i = this.ports.indexOf(port);
if (i >= 0) {
this.ports.splice(i, 1);
} else {
@@ -355,7 +359,7 @@ class ChromeNotifier implements Notifier {
}
notify() {
- for (let p of this.ports) {
+ for (const p of this.ports) {
p.postMessage({ notify: true });
}
}
@@ -365,7 +369,7 @@ class ChromeNotifier implements Notifier {
/**
* Mapping from tab ID to payment information (if any).
*/
-let paymentRequestCookies: { [n: number]: any } = {};
+const paymentRequestCookies: { [n: number]: any } = {};
/**
@@ -376,19 +380,19 @@ let paymentRequestCookies: { [n: number]: any } = {};
*/
function handleHttpPayment(headerList: chrome.webRequest.HttpHeader[], url: string, tabId: number): any {
const headers: { [s: string]: string } = {};
- for (let kv of headerList) {
+ for (const kv of headerList) {
if (kv.value) {
headers[kv.name.toLowerCase()] = kv.value;
}
}
- let fields = {
- contract_url: headers["x-taler-contract-url"],
+ const fields = {
contract_query: headers["x-taler-contract-query"],
+ contract_url: headers["x-taler-contract-url"],
offer_url: headers["x-taler-offer-url"],
- }
+ };
- let talerHeaderFound = Object.keys(fields).filter((x: any) => (fields as any)[x]).length !== 0;
+ const talerHeaderFound = Object.keys(fields).filter((x: any) => (fields as any)[x]).length !== 0;
if (!talerHeaderFound) {
// looks like it's not a taler request, it might be
@@ -397,27 +401,26 @@ function handleHttpPayment(headerList: chrome.webRequest.HttpHeader[], url: stri
return;
}
- let payDetail = {
+ const payDetail = {
contract_url: fields.contract_url,
offer_url: fields.offer_url,
};
- console.log("got pay detail", payDetail)
+ console.log("got pay detail", payDetail);
// This cookie will be read by the injected content script
// in the tab that displays the page.
paymentRequestCookies[tabId] = {
- type: "pay",
payDetail,
+ type: "pay",
};
}
-
function handleBankRequest(wallet: Wallet, headerList: chrome.webRequest.HttpHeader[],
- url: string, tabId: number): any {
+ url: string, tabId: number): any {
const headers: { [s: string]: string } = {};
- for (let kv of headerList) {
+ for (const kv of headerList) {
if (kv.value) {
headers[kv.name.toLowerCase()] = kv.value;
}
@@ -432,7 +435,7 @@ function handleBankRequest(wallet: Wallet, headerList: chrome.webRequest.HttpHea
const amount = headers["x-taler-amount"];
if (amount) {
- let callbackUrl = headers["x-taler-callback-url"];
+ const callbackUrl = headers["x-taler-callback-url"];
if (!callbackUrl) {
console.log("202 not understood (X-Taler-Callback-Url missing)");
return;
@@ -441,30 +444,29 @@ function handleBankRequest(wallet: Wallet, headerList: chrome.webRequest.HttpHea
try {
amountParsed = JSON.parse(amount);
} catch (e) {
- let uri = new URI(chrome.extension.getURL("/src/pages/error.html"));
- let p = {
+ const uri = new URI(chrome.extension.getURL("/src/pages/error.html"));
+ const p = {
message: `Can't parse amount ("${amount}"): ${e.message}`,
};
- let redirectUrl = uri.query(p).href();
+ const redirectUrl = uri.query(p).href();
// FIXME: use direct redirect when https://bugzilla.mozilla.org/show_bug.cgi?id=707624 is fixed
chrome.tabs.update(tabId, {url: redirectUrl});
return;
}
- let wtTypes = headers["x-taler-wt-types"];
+ const wtTypes = headers["x-taler-wt-types"];
if (!wtTypes) {
console.log("202 not understood (X-Taler-Wt-Types missing)");
return;
}
- let params = {
- amount: amount,
- callback_url: new URI(callbackUrl)
- .absoluteTo(url),
+ const params = {
+ amount,
bank_url: url,
- wt_types: wtTypes,
+ callback_url: new URI(callbackUrl) .absoluteTo(url),
suggested_exchange_url: headers["x-taler-suggested-exchange"],
+ wt_types: wtTypes,
};
- let uri = new URI(chrome.extension.getURL("/src/pages/confirm-create-reserve.html"));
- let redirectUrl = uri.query(params).href();
+ const uri = new URI(chrome.extension.getURL("/src/pages/confirm-create-reserve.html"));
+ const redirectUrl = uri.query(params).href();
console.log("redirecting to", redirectUrl);
// FIXME: use direct redirect when https://bugzilla.mozilla.org/show_bug.cgi?id=707624 is fixed
chrome.tabs.update(tabId, {url: redirectUrl});
@@ -484,21 +486,21 @@ function clearRateLimitCache() {
export async function wxMain() {
window.onerror = (m, source, lineno, colno, error) => {
logging.record("error", m + error, undefined, source || "(unknown)", lineno || 0, colno || 0);
- }
+ };
chrome.browserAction.setBadgeText({ text: "" });
const badge = new ChromeBadge();
- chrome.tabs.query({}, function (tabs) {
- for (let tab of tabs) {
+ chrome.tabs.query({}, (tabs) => {
+ for (const tab of tabs) {
if (!tab.url || !tab.id) {
return;
}
- let uri = new URI(tab.url);
+ const uri = new URI(tab.url);
if (uri.protocol() === "http" || uri.protocol() === "https") {
console.log("injecting into existing tab", tab.id);
chrome.tabs.executeScript(tab.id, { file: "/dist/contentScript-bundle.js" });
- let code = `
+ const code = `
if (("taler" in window) || document.documentElement.getAttribute("data-taler-nojs")) {
document.dispatchEvent(new Event("taler-probe-result"));
}
@@ -511,13 +513,13 @@ export async function wxMain() {
const tabTimers: {[n: number]: number[]} = {};
chrome.tabs.onRemoved.addListener((tabId, changeInfo) => {
- let tt = tabTimers[tabId] || [];
- for (let t of tt) {
+ const tt = tabTimers[tabId] || [];
+ for (const t of tt) {
chrome.extension.getBackgroundPage().clearTimeout(t);
}
});
chrome.tabs.onUpdated.addListener((tabId, changeInfo) => {
- if (changeInfo.status !== 'complete') {
+ if (changeInfo.status !== "complete") {
return;
}
const timers: number[] = [];
@@ -525,7 +527,7 @@ export async function wxMain() {
const addRun = (dt: number) => {
const id = chrome.extension.getBackgroundPage().setTimeout(run, dt);
timers.push(id);
- }
+ };
const run = () => {
timers.shift();
@@ -536,11 +538,11 @@ export async function wxMain() {
if (!tab.url || !tab.id) {
return;
}
- let uri = new URI(tab.url);
+ const uri = new URI(tab.url);
if (!(uri.protocol() === "http" || uri.protocol() === "https")) {
return;
}
- let code = `
+ const code = `
if (("taler" in window) || document.documentElement.getAttribute("data-taler-nojs")) {
document.dispatchEvent(new Event("taler-probe-result"));
}
@@ -600,7 +602,6 @@ export async function wxMain() {
}
-
/**
* Return a promise that resolves
* to the taler wallet db.
@@ -620,13 +621,13 @@ function openTalerDb(): Promise<IDBDatabase> {
switch (e.oldVersion) {
case 0: // DB does not exist yet
- for (let n in Stores) {
+ for (const n in Stores) {
if ((Stores as any)[n] instanceof Store) {
- let si: Store<any> = (Stores as any)[n];
+ const si: Store<any> = (Stores as any)[n];
const s = db.createObjectStore(si.name, si.storeParams);
- for (let indexName in (si as any)) {
+ for (const indexName in (si as any)) {
if ((si as any)[indexName] instanceof Index) {
- let ii: Index<any, any> = (si as any)[indexName];
+ const ii: Index<any, any> = (si as any)[indexName];
s.createIndex(ii.indexName, ii.keyPath);
}
}
@@ -649,31 +650,32 @@ function openTalerDb(): Promise<IDBDatabase> {
function exportDb(db: IDBDatabase): Promise<any> {
- let dump = {
+ const dump = {
name: db.name,
- version: db.version,
stores: {} as {[s: string]: any},
+ version: db.version,
};
return new Promise((resolve, reject) => {
- let tx = db.transaction(Array.from(db.objectStoreNames));
+ const tx = db.transaction(Array.from(db.objectStoreNames));
tx.addEventListener("complete", () => {
resolve(dump);
});
+ // tslint:disable-next-line:prefer-for-of
for (let i = 0; i < db.objectStoreNames.length; i++) {
- let name = db.objectStoreNames[i];
- let storeDump = {} as {[s: string]: any};
+ const name = db.objectStoreNames[i];
+ const storeDump = {} as {[s: string]: any};
dump.stores[name] = storeDump;
- let store = tx.objectStore(name)
- .openCursor()
- .addEventListener("success", (e: Event) => {
- let cursor = (e.target as any).result;
- if (cursor) {
- storeDump[cursor.key] = cursor.value;
- cursor.continue();
- }
- });
+ tx.objectStore(name)
+ .openCursor()
+ .addEventListener("success", (e: Event) => {
+ const cursor = (e.target as any).result;
+ if (cursor) {
+ storeDump[cursor.key] = cursor.value;
+ cursor.continue();
+ }
+ });
}
});
}
@@ -682,17 +684,20 @@ function exportDb(db: IDBDatabase): Promise<any> {
function importDb(db: IDBDatabase, dump: any): Promise<void> {
console.log("importing db", dump);
return new Promise<void>((resolve, reject) => {
- let tx = db.transaction(Array.from(db.objectStoreNames), "readwrite");
- for (let storeName in dump.stores) {
- let objects = [];
- for (let key in dump.stores[storeName]) {
- objects.push(dump.stores[storeName][key]);
- }
- console.log(`importing ${objects.length} records into ${storeName}`);
- let store = tx.objectStore(storeName);
- let clearReq = store.clear();
- for (let obj of objects) {
- store.put(obj);
+ const tx = db.transaction(Array.from(db.objectStoreNames), "readwrite");
+ if (dump.stores) {
+ for (const storeName in dump.stores) {
+ const objects = [];
+ const dumpStore = dump.stores[storeName];
+ for (const key in dumpStore) {
+ objects.push(dumpStore[key]);
+ }
+ console.log(`importing ${objects.length} records into ${storeName}`);
+ const store = tx.objectStore(storeName);
+ const clearReq = store.clear();
+ for (const obj of objects) {
+ store.put(obj);
+ }
}
}
tx.addEventListener("complete", () => {