put all crypto into backend
This commit is contained in:
parent
81428771b8
commit
2760591d4d
@ -18,6 +18,9 @@
|
|||||||
import {PreCoin} from "./types";
|
import {PreCoin} from "./types";
|
||||||
import {Reserve} from "./types";
|
import {Reserve} from "./types";
|
||||||
import {Denomination} from "./types";
|
import {Denomination} from "./types";
|
||||||
|
import {Offer} from "./wallet";
|
||||||
|
import {CoinWithDenom} from "./wallet";
|
||||||
|
import {PayCoinInfo} from "./types";
|
||||||
export class CryptoApi {
|
export class CryptoApi {
|
||||||
private nextRpcId: number = 1;
|
private nextRpcId: number = 1;
|
||||||
private rpcRegistry = {};
|
private rpcRegistry = {};
|
||||||
@ -66,9 +69,25 @@ export class CryptoApi {
|
|||||||
return this.doRpc("createPreCoin", denom, reserve);
|
return this.doRpc("createPreCoin", denom, reserve);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hashRsaPub(rsaPub: string): Promise<string> {
|
||||||
|
return this.doRpc("hashRsaPub", rsaPub);
|
||||||
|
}
|
||||||
|
|
||||||
isValidDenom(denom: Denomination,
|
isValidDenom(denom: Denomination,
|
||||||
masterPub: string): Promise<boolean> {
|
masterPub: string): Promise<boolean> {
|
||||||
return this.doRpc("isValidDenom", denom, masterPub);
|
return this.doRpc("isValidDenom", denom, masterPub);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
signDeposit(offer: Offer,
|
||||||
|
cds: CoinWithDenom[]): Promise<PayCoinInfo> {
|
||||||
|
return this.doRpc("signDeposit", offer, cds);
|
||||||
|
}
|
||||||
|
|
||||||
|
createEddsaKeypair(): Promise<{priv: string, pub: string}> {
|
||||||
|
return this.doRpc("createEddsaKeypair");
|
||||||
|
}
|
||||||
|
|
||||||
|
rsaUnblind(sig: string, bk: string, pk: string): Promise<string> {
|
||||||
|
return this.doRpc("rsaUnblind", sig, bk, pk);
|
||||||
|
}
|
||||||
}
|
}
|
@ -23,8 +23,11 @@ import {Denomination} from "./types";
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
import * as native from "./emscriptif";
|
import * as native from "./emscriptif";
|
||||||
import {PreCoin, Reserve} from "./types";
|
import {PreCoin, Reserve, PayCoinInfo} from "./types";
|
||||||
import create = chrome.alarms.create;
|
import create = chrome.alarms.create;
|
||||||
|
import {Offer} from "./wallet";
|
||||||
|
import {CoinWithDenom} from "./wallet";
|
||||||
|
import {CoinPaySig} from "./types";
|
||||||
|
|
||||||
|
|
||||||
export function main(worker: Worker) {
|
export function main(worker: Worker) {
|
||||||
@ -58,7 +61,8 @@ namespace RpcFunctions {
|
|||||||
* Create a pre-coin of the given denomination to be withdrawn from then given
|
* Create a pre-coin of the given denomination to be withdrawn from then given
|
||||||
* reserve.
|
* reserve.
|
||||||
*/
|
*/
|
||||||
export function createPreCoin(denom: Denomination, reserve: Reserve): PreCoin {
|
export function createPreCoin(denom: Denomination,
|
||||||
|
reserve: Reserve): PreCoin {
|
||||||
let reservePriv = new native.EddsaPrivateKey();
|
let reservePriv = new native.EddsaPrivateKey();
|
||||||
reservePriv.loadCrock(reserve.reserve_priv);
|
reservePriv.loadCrock(reserve.reserve_priv);
|
||||||
let reservePub = new native.EddsaPublicKey();
|
let reservePub = new native.EddsaPublicKey();
|
||||||
@ -107,7 +111,7 @@ namespace RpcFunctions {
|
|||||||
|
|
||||||
|
|
||||||
export function isValidDenom(denom: Denomination,
|
export function isValidDenom(denom: Denomination,
|
||||||
masterPub: string): boolean {
|
masterPub: string): boolean {
|
||||||
let p = new native.DenominationKeyValidityPS({
|
let p = new native.DenominationKeyValidityPS({
|
||||||
master: native.EddsaPublicKey.fromCrock(masterPub),
|
master: native.EddsaPublicKey.fromCrock(masterPub),
|
||||||
denom_hash: native.RsaPublicKey.fromCrock(denom.denom_pub)
|
denom_hash: native.RsaPublicKey.fromCrock(denom.denom_pub)
|
||||||
@ -134,4 +138,85 @@ namespace RpcFunctions {
|
|||||||
nativePub);
|
nativePub);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function hashRsaPub(rsaPub: string): string {
|
||||||
|
return native.RsaPublicKey.fromCrock(rsaPub)
|
||||||
|
.encode()
|
||||||
|
.hash()
|
||||||
|
.toCrock();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function createEddsaKeypair(): {priv: string, pub: string} {
|
||||||
|
const priv = native.EddsaPrivateKey.create();
|
||||||
|
const pub = priv.getPublicKey();
|
||||||
|
return {priv: priv.toCrock(), pub: pub.toCrock()};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function rsaUnblind(sig, bk, pk): string {
|
||||||
|
let denomSig = native.rsaUnblind(native.RsaSignature.fromCrock(sig),
|
||||||
|
native.RsaBlindingKey.fromCrock(bk),
|
||||||
|
native.RsaPublicKey.fromCrock(pk));
|
||||||
|
return denomSig.encode().toCrock()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate updated coins (to store in the database)
|
||||||
|
* and deposit permissions for each given coin.
|
||||||
|
*/
|
||||||
|
export function signDeposit(offer: Offer,
|
||||||
|
cds: CoinWithDenom[]): PayCoinInfo {
|
||||||
|
let ret = [];
|
||||||
|
let amountSpent = native.Amount.getZero(cds[0].coin.currentAmount.currency);
|
||||||
|
let amountRemaining = new native.Amount(offer.contract.amount);
|
||||||
|
for (let cd of cds) {
|
||||||
|
let coinSpend;
|
||||||
|
|
||||||
|
if (amountRemaining.value == 0 && amountRemaining.fraction == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (amountRemaining.cmp(new native.Amount(cd.coin.currentAmount)) < 0) {
|
||||||
|
coinSpend = new native.Amount(amountRemaining.toJson());
|
||||||
|
} else {
|
||||||
|
coinSpend = new native.Amount(cd.coin.currentAmount);
|
||||||
|
}
|
||||||
|
|
||||||
|
amountSpent.add(coinSpend);
|
||||||
|
amountRemaining.sub(coinSpend);
|
||||||
|
|
||||||
|
let newAmount = new native.Amount(cd.coin.currentAmount);
|
||||||
|
newAmount.sub(coinSpend);
|
||||||
|
cd.coin.currentAmount = newAmount.toJson();
|
||||||
|
|
||||||
|
let d = new native.DepositRequestPS({
|
||||||
|
h_contract: native.HashCode.fromCrock(offer.H_contract),
|
||||||
|
h_wire: native.HashCode.fromCrock(offer.contract.H_wire),
|
||||||
|
amount_with_fee: coinSpend.toNbo(),
|
||||||
|
coin_pub: native.EddsaPublicKey.fromCrock(cd.coin.coinPub),
|
||||||
|
deposit_fee: new native.Amount(cd.denom.fee_deposit).toNbo(),
|
||||||
|
merchant: native.EddsaPublicKey.fromCrock(offer.contract.merchant_pub),
|
||||||
|
refund_deadline: native.AbsoluteTimeNbo.fromTalerString(offer.contract.refund_deadline),
|
||||||
|
timestamp: native.AbsoluteTimeNbo.fromTalerString(offer.contract.timestamp),
|
||||||
|
transaction_id: native.UInt64.fromNumber(offer.contract.transaction_id),
|
||||||
|
});
|
||||||
|
|
||||||
|
let coinSig = native.eddsaSign(d.toPurpose(),
|
||||||
|
native.EddsaPrivateKey.fromCrock(cd.coin.coinPriv))
|
||||||
|
.toCrock();
|
||||||
|
|
||||||
|
let s: CoinPaySig = {
|
||||||
|
coin_sig: coinSig,
|
||||||
|
coin_pub: cd.coin.coinPub,
|
||||||
|
ub_sig: cd.coin.denomSig,
|
||||||
|
denom_pub: cd.coin.denomPub,
|
||||||
|
f: coinSpend.toJson(),
|
||||||
|
};
|
||||||
|
ret.push({sig: s, updatedCoin: cd.coin});
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -120,12 +120,36 @@ export interface PreCoin {
|
|||||||
coinValue: AmountJson;
|
coinValue: AmountJson;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export interface Reserve {
|
export interface Reserve {
|
||||||
mint_base_url: string
|
mint_base_url: string
|
||||||
reserve_priv: string;
|
reserve_priv: string;
|
||||||
reserve_pub: string;
|
reserve_pub: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface CoinPaySig {
|
||||||
|
coin_sig: string;
|
||||||
|
coin_pub: string;
|
||||||
|
ub_sig: string;
|
||||||
|
denom_pub: string;
|
||||||
|
f: AmountJson;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface Coin {
|
||||||
|
coinPub: string;
|
||||||
|
coinPriv: string;
|
||||||
|
denomPub: string;
|
||||||
|
denomSig: string;
|
||||||
|
currentAmount: AmountJson;
|
||||||
|
mintBaseUrl: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export type PayCoinInfo = Array<{ updatedCoin: Coin, sig: CoinPaySig }>;
|
||||||
|
|
||||||
|
|
||||||
export namespace Amounts {
|
export namespace Amounts {
|
||||||
export interface Result {
|
export interface Result {
|
||||||
amount: AmountJson;
|
amount: AmountJson;
|
||||||
|
@ -27,10 +27,12 @@ import {HttpResponse, RequestException} from "./http";
|
|||||||
import {Query} from "./query";
|
import {Query} from "./query";
|
||||||
import {Checkable} from "./checkable";
|
import {Checkable} from "./checkable";
|
||||||
import {canonicalizeBaseUrl} from "./helpers";
|
import {canonicalizeBaseUrl} from "./helpers";
|
||||||
import {ReserveCreationInfo} from "./types";
|
import {ReserveCreationInfo, Amounts} from "./types";
|
||||||
import {PreCoin} from "./types";
|
import {PreCoin} from "./types";
|
||||||
import {Reserve} from "./types";
|
import {Reserve} from "./types";
|
||||||
import {CryptoApi} from "./cryptoApi";
|
import {CryptoApi} from "./cryptoApi";
|
||||||
|
import {Coin} from "./types";
|
||||||
|
import {PayCoinInfo} from "./types";
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
@ -68,16 +70,6 @@ export class KeysJson {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export interface Coin {
|
|
||||||
coinPub: string;
|
|
||||||
coinPriv: string;
|
|
||||||
denomPub: string;
|
|
||||||
denomSig: string;
|
|
||||||
currentAmount: AmountJson;
|
|
||||||
mintBaseUrl: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class MintInfo implements IMintInfo {
|
class MintInfo implements IMintInfo {
|
||||||
baseUrl: string;
|
baseUrl: string;
|
||||||
masterPublicKey: string;
|
masterPublicKey: string;
|
||||||
@ -147,14 +139,10 @@ class MintInfo implements IMintInfo {
|
|||||||
if (!valid) {
|
if (!valid) {
|
||||||
throw Error("signature on denomination invalid");
|
throw Error("signature on denomination invalid");
|
||||||
}
|
}
|
||||||
|
return cryptoApi.hashRsaPub(newDenom.denom_pub);
|
||||||
let d: Denomination = Object.assign({}, newDenom);
|
})
|
||||||
d.pub_hash = native.RsaPublicKey.fromCrock(d.denom_pub)
|
.then((h) => {
|
||||||
.encode()
|
this.denoms.push(Object.assign({}, newDenom, {pub_hash: h}));
|
||||||
.hash()
|
|
||||||
.toCrock();
|
|
||||||
this.denoms.push(d);
|
|
||||||
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -302,8 +290,6 @@ export interface Badge {
|
|||||||
setColor(c: string): void;
|
setColor(c: string): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
type PayCoinInfo = Array<{ updatedCoin: Coin, sig: CoinPaySig }>;
|
|
||||||
|
|
||||||
|
|
||||||
function deepEquals(x, y) {
|
function deepEquals(x, y) {
|
||||||
if (x === y) {
|
if (x === y) {
|
||||||
@ -362,11 +348,8 @@ function copy(o) {
|
|||||||
* Rank two denomination by how desireable it is to withdraw them,
|
* Rank two denomination by how desireable it is to withdraw them,
|
||||||
* based on their fees and value.
|
* based on their fees and value.
|
||||||
*/
|
*/
|
||||||
function rankDenom(denom1: any, denom2: any) {
|
function rankDenom(denom1: Denomination, denom2: Denomination) {
|
||||||
// Slow ... we should find a better way than to convert it evert time.
|
return (-1) * Amounts.cmp(denom1.value, denom2.value);
|
||||||
let v1 = new native.Amount(denom1.value);
|
|
||||||
let v2 = new native.Amount(denom2.value);
|
|
||||||
return (-1) * v1.cmp(v2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -427,65 +410,6 @@ export class Wallet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate updated coins (to store in the database)
|
|
||||||
* and deposit permissions for each given coin.
|
|
||||||
*/
|
|
||||||
private static signDeposit(offer: Offer,
|
|
||||||
cds: CoinWithDenom[]): PayCoinInfo {
|
|
||||||
let ret = [];
|
|
||||||
let amountSpent = native.Amount.getZero(cds[0].coin.currentAmount.currency);
|
|
||||||
let amountRemaining = new native.Amount(offer.contract.amount);
|
|
||||||
cds = copy(cds);
|
|
||||||
for (let cd of cds) {
|
|
||||||
let coinSpend;
|
|
||||||
|
|
||||||
if (amountRemaining.value == 0 && amountRemaining.fraction == 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (amountRemaining.cmp(new native.Amount(cd.coin.currentAmount)) < 0) {
|
|
||||||
coinSpend = new native.Amount(amountRemaining.toJson());
|
|
||||||
} else {
|
|
||||||
coinSpend = new native.Amount(cd.coin.currentAmount);
|
|
||||||
}
|
|
||||||
|
|
||||||
amountSpent.add(coinSpend);
|
|
||||||
amountRemaining.sub(coinSpend);
|
|
||||||
|
|
||||||
let newAmount = new native.Amount(cd.coin.currentAmount);
|
|
||||||
newAmount.sub(coinSpend);
|
|
||||||
cd.coin.currentAmount = newAmount.toJson();
|
|
||||||
|
|
||||||
let d = new native.DepositRequestPS({
|
|
||||||
h_contract: native.HashCode.fromCrock(offer.H_contract),
|
|
||||||
h_wire: native.HashCode.fromCrock(offer.contract.H_wire),
|
|
||||||
amount_with_fee: coinSpend.toNbo(),
|
|
||||||
coin_pub: native.EddsaPublicKey.fromCrock(cd.coin.coinPub),
|
|
||||||
deposit_fee: new native.Amount(cd.denom.fee_deposit).toNbo(),
|
|
||||||
merchant: native.EddsaPublicKey.fromCrock(offer.contract.merchant_pub),
|
|
||||||
refund_deadline: native.AbsoluteTimeNbo.fromTalerString(offer.contract.refund_deadline),
|
|
||||||
timestamp: native.AbsoluteTimeNbo.fromTalerString(offer.contract.timestamp),
|
|
||||||
transaction_id: native.UInt64.fromNumber(offer.contract.transaction_id),
|
|
||||||
});
|
|
||||||
|
|
||||||
let coinSig = native.eddsaSign(d.toPurpose(),
|
|
||||||
native.EddsaPrivateKey.fromCrock(cd.coin.coinPriv))
|
|
||||||
.toCrock();
|
|
||||||
|
|
||||||
let s: CoinPaySig = {
|
|
||||||
coin_sig: coinSig,
|
|
||||||
coin_pub: cd.coin.coinPub,
|
|
||||||
ub_sig: cd.coin.denomSig,
|
|
||||||
denom_pub: cd.coin.denomPub,
|
|
||||||
f: coinSpend.toJson(),
|
|
||||||
};
|
|
||||||
ret.push({sig: s, updatedCoin: cd.coin});
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get mints and associated coins that are still spendable,
|
* Get mints and associated coins that are still spendable,
|
||||||
* but only if the sum the coins' remaining value exceeds the payment amount.
|
* but only if the sum the coins' remaining value exceeds the payment amount.
|
||||||
@ -647,9 +571,10 @@ export class Wallet {
|
|||||||
}
|
}
|
||||||
console.log("about to record ...");
|
console.log("about to record ...");
|
||||||
let mintUrl = Object.keys(mcs)[0];
|
let mintUrl = Object.keys(mcs)[0];
|
||||||
let ds = Wallet.signDeposit(offer, mcs[mintUrl]);
|
|
||||||
return this.recordConfirmPay(offer, ds, mintUrl)
|
return this.cryptoApi.signDeposit(offer, mcs[mintUrl])
|
||||||
.then((() => ({})));
|
.then((ds) => this.recordConfirmPay(offer, ds, mintUrl))
|
||||||
|
.then(() => ({}));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -711,44 +636,43 @@ export class Wallet {
|
|||||||
* Create a reserve, but do not flag it as confirmed yet.
|
* Create a reserve, but do not flag it as confirmed yet.
|
||||||
*/
|
*/
|
||||||
createReserve(req: CreateReserveRequest): Promise<CreateReserveResponse> {
|
createReserve(req: CreateReserveRequest): Promise<CreateReserveResponse> {
|
||||||
const reservePriv = native.EddsaPrivateKey.create();
|
return this.cryptoApi.createEddsaKeypair().then((keypair) => {
|
||||||
const reservePub = reservePriv.getPublicKey();
|
const now = (new Date).getTime();
|
||||||
|
const canonMint = canonicalizeBaseUrl(req.mint);
|
||||||
|
|
||||||
const now = (new Date).getTime();
|
const reserveRecord = {
|
||||||
const canonMint = canonicalizeBaseUrl(req.mint);
|
reserve_pub: keypair.pub,
|
||||||
|
reserve_priv: keypair.priv,
|
||||||
const reserveRecord = {
|
mint_base_url: canonMint,
|
||||||
reserve_pub: reservePub.toCrock(),
|
created: now,
|
||||||
reserve_priv: reservePriv.toCrock(),
|
last_query: null,
|
||||||
mint_base_url: canonMint,
|
current_amount: null,
|
||||||
created: now,
|
requested_amount: req.amount,
|
||||||
last_query: null,
|
confirmed: false,
|
||||||
current_amount: null,
|
};
|
||||||
requested_amount: req.amount,
|
|
||||||
confirmed: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
const historyEntry = {
|
const historyEntry = {
|
||||||
type: "create-reserve",
|
type: "create-reserve",
|
||||||
timestamp: now,
|
timestamp: now,
|
||||||
detail: {
|
detail: {
|
||||||
requestedAmount: req.amount,
|
requestedAmount: req.amount,
|
||||||
reservePub: reserveRecord.reserve_pub,
|
reservePub: reserveRecord.reserve_pub,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return Query(this.db)
|
return Query(this.db)
|
||||||
.put("reserves", reserveRecord)
|
.put("reserves", reserveRecord)
|
||||||
.put("history", historyEntry)
|
.put("history", historyEntry)
|
||||||
.finish()
|
.finish()
|
||||||
.then(() => {
|
.then(() => {
|
||||||
let r: CreateReserveResponse = {
|
let r: CreateReserveResponse = {
|
||||||
mint: canonMint,
|
mint: canonMint,
|
||||||
reservePub: reservePub.toCrock(),
|
reservePub: keypair.pub,
|
||||||
};
|
};
|
||||||
return r;
|
return r;
|
||||||
});
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -806,18 +730,19 @@ export class Wallet {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
let r = JSON.parse(resp.responseText);
|
let r = JSON.parse(resp.responseText);
|
||||||
let denomSig = native.rsaUnblind(native.RsaSignature.fromCrock(r.ev_sig),
|
return this.cryptoApi.rsaUnblind(r.ev_sig, pc.blindingKey, pc.denomPub)
|
||||||
native.RsaBlindingKey.fromCrock(pc.blindingKey),
|
.then((denomSig) => {
|
||||||
native.RsaPublicKey.fromCrock(pc.denomPub));
|
let coin: Coin = {
|
||||||
let coin: Coin = {
|
coinPub: pc.coinPub,
|
||||||
coinPub: pc.coinPub,
|
coinPriv: pc.coinPriv,
|
||||||
coinPriv: pc.coinPriv,
|
denomPub: pc.denomPub,
|
||||||
denomPub: pc.denomPub,
|
denomSig: denomSig,
|
||||||
denomSig: denomSig.encode().toCrock(),
|
currentAmount: pc.coinValue,
|
||||||
currentAmount: pc.coinValue,
|
mintBaseUrl: pc.mintBaseUrl,
|
||||||
mintBaseUrl: pc.mintBaseUrl,
|
};
|
||||||
};
|
return coin;
|
||||||
return coin;
|
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -965,7 +890,7 @@ export class Wallet {
|
|||||||
console.log("using old mint");
|
console.log("using old mint");
|
||||||
}
|
}
|
||||||
|
|
||||||
return mintInfo.mergeKeys(mintKeysJson, this)
|
return mintInfo.mergeKeys(mintKeysJson, this.cryptoApi)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
return Query(this.db)
|
return Query(this.db)
|
||||||
.put("mints", mintInfo)
|
.put("mints", mintInfo)
|
||||||
|
Loading…
Reference in New Issue
Block a user