aboutsummaryrefslogtreecommitdiff
path: root/packages/taler-util/src
diff options
context:
space:
mode:
Diffstat (limited to 'packages/taler-util/src')
-rw-r--r--packages/taler-util/src/http-common.ts29
-rw-r--r--packages/taler-util/src/payto.ts22
-rw-r--r--packages/taler-util/src/taler-crypto.ts5
-rw-r--r--packages/taler-util/src/taler-types.ts135
4 files changed, 171 insertions, 20 deletions
diff --git a/packages/taler-util/src/http-common.ts b/packages/taler-util/src/http-common.ts
index 4f6aaaf44..93cf9bba0 100644
--- a/packages/taler-util/src/http-common.ts
+++ b/packages/taler-util/src/http-common.ts
@@ -19,7 +19,12 @@
import { CancellationToken } from "./CancellationToken.js";
import { Codec } from "./codec.js";
import { j2s } from "./helpers.js";
-import { TalerError, makeErrorDetail } from "./index.js";
+import {
+ TalerError,
+ base64FromArrayBuffer,
+ makeErrorDetail,
+ stringToBytes,
+} from "./index.js";
import { Logger } from "./logging.js";
import { TalerErrorCode } from "./taler-error-codes.js";
import { Duration, AbsoluteTime } from "./time.js";
@@ -306,6 +311,16 @@ export async function readSuccessResponseJsonOrThrow<T>(
throwUnexpectedRequestError(httpResponse, r.talerErrorResponse);
}
+export async function expectSuccessResponseOrThrow<T>(
+ httpResponse: HttpResponse,
+): Promise<void> {
+ if (httpResponse.status >= 200 && httpResponse.status <= 299) {
+ return;
+ }
+ const errResp = await readTalerErrorResponse(httpResponse);
+ throwUnexpectedRequestError(httpResponse, errResp);
+}
+
export async function readSuccessResponseTextOrErrorCode<T>(
httpResponse: HttpResponse,
): Promise<ResponseOrError<string>> {
@@ -452,3 +467,15 @@ export function getDefaultHeaders(method: string): Record<string, string> {
return headers;
}
+
+/**
+ * Helper function to generate the "Authorization" HTTP header.
+ */
+export function makeBasicAuthHeader(
+ username: string,
+ password: string,
+): string {
+ const auth = `${username}:${password}`;
+ const authEncoded: string = base64FromArrayBuffer(stringToBytes(auth));
+ return `Basic ${authEncoded}`;
+}
diff --git a/packages/taler-util/src/payto.ts b/packages/taler-util/src/payto.ts
index dd35b44be..2b0af4cc2 100644
--- a/packages/taler-util/src/payto.ts
+++ b/packages/taler-util/src/payto.ts
@@ -239,3 +239,25 @@ export function parsePaytoUri(s: string): PaytoUri | undefined {
isKnown: false,
};
}
+
+export function talerPaytoFromExchangeReserve(
+ exchangeBaseUrl: string,
+ reservePub: string,
+): string {
+ const url = new URL(exchangeBaseUrl);
+ let proto: string;
+ if (url.protocol === "http:") {
+ proto = "taler-reserve-http";
+ } else if (url.protocol === "https:") {
+ proto = "taler-reserve";
+ } else {
+ throw Error(`unsupported exchange base URL protocol (${url.protocol})`);
+ }
+
+ let path = url.pathname;
+ if (!path.endsWith("/")) {
+ path = path + "/";
+ }
+
+ return `payto://${proto}/${url.host}${url.pathname}${reservePub}`;
+}
diff --git a/packages/taler-util/src/taler-crypto.ts b/packages/taler-util/src/taler-crypto.ts
index 396ac89e1..cc9c706ba 100644
--- a/packages/taler-util/src/taler-crypto.ts
+++ b/packages/taler-util/src/taler-crypto.ts
@@ -1004,7 +1004,7 @@ export enum TalerSignaturePurpose {
SYNC_BACKUP_UPLOAD = 1450,
}
-export const enum WalletAccountMergeFlags {
+export enum WalletAccountMergeFlags {
/**
* Not a legal mode!
*/
@@ -1260,7 +1260,8 @@ export namespace AgeRestriction {
}
const PublishedAgeRestrictionBaseKey: Edx25519PublicKey = decodeCrock(
- "CH0VKFDZ2GWRWHQBBGEK9MWV5YDQVJ0RXEE0KYT3NMB69F0R96TG");
+ "CH0VKFDZ2GWRWHQBBGEK9MWV5YDQVJ0RXEE0KYT3NMB69F0R96TG",
+ );
export async function restrictionCommitSeeded(
ageMask: number,
diff --git a/packages/taler-util/src/taler-types.ts b/packages/taler-util/src/taler-types.ts
index 178da87da..17900129c 100644
--- a/packages/taler-util/src/taler-types.ts
+++ b/packages/taler-util/src/taler-types.ts
@@ -25,7 +25,7 @@
* Imports.
*/
-import { codecForAmountString } from "./amounts.js";
+import { Amounts, codecForAmountString } from "./amounts.js";
import {
buildCodecForObject,
buildCodecForUnion,
@@ -719,16 +719,12 @@ export class ExchangeSignKeyJson {
* Structure that the exchange gives us in /keys.
*/
export class ExchangeKeysJson {
-
/**
* Canonical, public base URL of the exchange.
*/
base_url: string;
- /**
- * List of offered denominations.
- */
- denoms: ExchangeDenomination[];
+ currency: string;
/**
* The exchange's master public key.
@@ -764,6 +760,111 @@ export class ExchangeKeysJson {
reserve_closing_delay: TalerProtocolDuration;
global_fees: GlobalFees[];
+
+ accounts: AccountInfo[];
+
+ wire_fees: { [methodName: string]: WireFeesJson[] };
+
+ denominations: DenomGroup[];
+}
+
+export type DenomGroup =
+ | DenomGroupRsa
+ | DenomGroupCs
+ | DenomGroupRsaAgeRestricted
+ | DenomGroupCsAgeRestricted;
+
+export interface DenomGroupCommon {
+ // How much are coins of this denomination worth?
+ value: AmountString;
+
+ // Fee charged by the exchange for withdrawing a coin of this denomination.
+ fee_withdraw: AmountString;
+
+ // Fee charged by the exchange for depositing a coin of this denomination.
+ fee_deposit: AmountString;
+
+ // Fee charged by the exchange for refreshing a coin of this denomination.
+ fee_refresh: AmountString;
+
+ // Fee charged by the exchange for refunding a coin of this denomination.
+ fee_refund: AmountString;
+
+ // XOR of all the SHA-512 hash values of the denominations' public keys
+ // in this group. Note that for hashing, the binary format of the
+ // public keys is used, and not their base32 encoding.
+ hash: HashCodeString;
+}
+
+export interface DenomCommon {
+ // Signature of TALER_DenominationKeyValidityPS.
+ master_sig: EddsaSignatureString;
+
+ // When does the denomination key become valid?
+ stamp_start: TalerProtocolTimestamp;
+
+ // When is it no longer possible to deposit coins
+ // of this denomination?
+ stamp_expire_withdraw: TalerProtocolTimestamp;
+
+ // Timestamp indicating by when legal disputes relating to these coins must
+ // be settled, as the exchange will afterwards destroy its evidence relating to
+ // transactions involving this coin.
+ stamp_expire_legal: TalerProtocolTimestamp;
+
+ stamp_expire_deposit: TalerProtocolTimestamp;
+
+ // Set to 'true' if the exchange somehow "lost"
+ // the private key. The denomination was not
+ // necessarily revoked, but still cannot be used
+ // to withdraw coins at this time (theoretically,
+ // the private key could be recovered in the
+ // future; coins signed with the private key
+ // remain valid).
+ lost?: boolean;
+}
+
+export type RsaPublicKeySring = string;
+export type AgeMask = number;
+
+/**
+ * 32-byte value representing a point on Curve25519.
+ */
+export type Cs25519Point = string;
+
+export interface DenomGroupRsa extends DenomGroupCommon {
+ cipher: "RSA";
+
+ denoms: ({
+ rsa_pub: RsaPublicKeySring;
+ } & DenomCommon)[];
+}
+
+export interface DenomGroupRsaAgeRestricted extends DenomGroupCommon {
+ cipher: "RSA+age_restricted";
+ age_mask: AgeMask;
+
+ denoms: ({
+ rsa_pub: RsaPublicKeySring;
+ } & DenomCommon)[];
+}
+
+export interface DenomGroupCs extends DenomGroupCommon {
+ cipher: "CS";
+ age_mask: AgeMask;
+
+ denoms: ({
+ cs_pub: Cs25519Point;
+ } & DenomCommon)[];
+}
+
+export interface DenomGroupCsAgeRestricted extends DenomGroupCommon {
+ cipher: "CS+age_restricted";
+ age_mask: AgeMask;
+
+ denoms: ({
+ cs_pub: Cs25519Point;
+ } & DenomCommon)[];
}
export interface GlobalFees {
@@ -847,10 +948,10 @@ export interface AccountInfo {
debit_restrictions?: any;
}
-export interface ExchangeWireJson {
- accounts: AccountInfo[];
- fees: { [methodName: string]: WireFeesJson[] };
-}
+/**
+ * @deprecated
+ */
+export interface ExchangeWireJson {}
/**
* Proposal returned from the contract URL.
@@ -1404,10 +1505,13 @@ export const codecForGlobalFees = (): Codec<GlobalFees> =>
.property("master_sig", codecForString())
.build("GlobalFees");
+// FIXME: Validate properly!
+export const codecForNgDenominations: Codec<DenomGroup> = codecForAny();
+
export const codecForExchangeKeysJson = (): Codec<ExchangeKeysJson> =>
buildCodecForObject<ExchangeKeysJson>()
- .property("denoms", codecForList(codecForDenomination()))
.property("base_url", codecForString())
+ .property("currency", codecForString())
.property("master_public_key", codecForString())
.property("auditors", codecForList(codecForAuditor()))
.property("list_issue_date", codecForTimestamp)
@@ -1416,6 +1520,9 @@ export const codecForExchangeKeysJson = (): Codec<ExchangeKeysJson> =>
.property("version", codecForString())
.property("reserve_closing_delay", codecForDuration)
.property("global_fees", codecForList(codecForGlobalFees()))
+ .property("accounts", codecForList(codecForAccountInfo()))
+ .property("wire_fees", codecForMap(codecForList(codecForWireFeesJson())))
+ .property("denominations", codecForList(codecForNgDenominations))
.build("ExchangeKeysJson");
export const codecForWireFeesJson = (): Codec<WireFeesJson> =>
@@ -1436,12 +1543,6 @@ export const codecForAccountInfo = (): Codec<AccountInfo> =>
.property("debit_restrictions", codecForAny())
.build("AccountInfo");
-export const codecForExchangeWireJson = (): Codec<ExchangeWireJson> =>
- buildCodecForObject<ExchangeWireJson>()
- .property("accounts", codecForList(codecForAccountInfo()))
- .property("fees", codecForMap(codecForList(codecForWireFeesJson())))
- .build("ExchangeWireJson");
-
export const codecForProposal = (): Codec<Proposal> =>
buildCodecForObject<Proposal>()
.property("contract_terms", codecForAny())