gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-wallet-core] branch master updated: -missing files


From: gnunet
Subject: [taler-wallet-core] branch master updated: -missing files
Date: Wed, 06 Sep 2023 11:44:21 +0200

This is an automated email from the git hooks/post-receive script.

dold pushed a commit to branch master
in repository wallet-core.

The following commit(s) were added to refs/heads/master by this push:
     new 07d71eb29 -missing files
07d71eb29 is described below

commit 07d71eb29704a148f7e7bb0c064cbbad056d5a50
Author: Florian Dold <florian@dold.me>
AuthorDate: Wed Sep 6 11:44:21 2023 +0200

    -missing files
---
 packages/taler-util/src/MerchantApiClient.ts  | 334 ++++++++++++++++++++++++++
 packages/taler-util/src/libeufin-api-types.ts |  31 +++
 2 files changed, 365 insertions(+)

diff --git a/packages/taler-util/src/MerchantApiClient.ts 
b/packages/taler-util/src/MerchantApiClient.ts
new file mode 100644
index 000000000..cf4788d9e
--- /dev/null
+++ b/packages/taler-util/src/MerchantApiClient.ts
@@ -0,0 +1,334 @@
+/*
+ This file is part of GNU Taler
+ (C) 2023 Taler Systems S.A.
+
+ GNU 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.
+
+ GNU 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
+ GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+
+import {
+  createPlatformHttpLib,
+  expectSuccessResponseOrThrow,
+  readSuccessResponseJsonOrThrow,
+} from "./http.js";
+import { FacadeCredentials } from "./libeufin-api-types.js";
+import { Logger } from "./logging.js";
+import {
+  MerchantReserveCreateConfirmation,
+  codecForMerchantReserveCreateConfirmation,
+  TippingReserveStatus,
+  MerchantInstancesResponse,
+  MerchantPostOrderRequest,
+  MerchantPostOrderResponse,
+  codecForMerchantPostOrderResponse,
+  MerchantOrderPrivateStatusResponse,
+  codecForMerchantOrderPrivateStatusResponse,
+  RewardCreateRequest,
+  RewardCreateConfirmation,
+  MerchantTemplateAddDetails,
+} from "./merchant-api-types.js";
+import { AmountString } from "./taler-types.js";
+import { TalerProtocolDuration } from "./time.js";
+
+const logger = new Logger("MerchantApiClient.ts");
+
+export interface MerchantAuthConfiguration {
+  method: "external" | "token";
+  token?: string;
+}
+
+// FIXME: Why do we need this? Describe / fix!
+export interface PartialMerchantInstanceConfig {
+  auth?: MerchantAuthConfiguration;
+  id: string;
+  name: string;
+  paytoUris: string[];
+  address?: unknown;
+  jurisdiction?: unknown;
+  defaultWireTransferDelay?: TalerProtocolDuration;
+  defaultPayDelay?: TalerProtocolDuration;
+}
+
+export interface CreateMerchantTippingReserveRequest {
+  // Amount that the merchant promises to put into the reserve
+  initial_balance: AmountString;
+
+  // Exchange the merchant intends to use for tipping
+  exchange_url: string;
+
+  // Desired wire method, for example "iban" or "x-taler-bank"
+  wire_method: string;
+}
+
+export interface DeleteTippingReserveArgs {
+  reservePub: string;
+  purge?: boolean;
+}
+
+export interface MerchantInstanceConfig {
+  accounts: MerchantBankAccount[];
+  auth: MerchantAuthConfiguration;
+  id: string;
+  name: string;
+  address: unknown;
+  jurisdiction: unknown;
+  use_stefan: boolean;
+  default_wire_transfer_delay: TalerProtocolDuration;
+  default_pay_delay: TalerProtocolDuration;
+}
+
+interface MerchantBankAccount {
+  // The payto:// URI where the wallet will send coins.
+  payto_uri: string;
+
+  // Optional base URL for a facade where the
+  // merchant backend can see incoming wire
+  // transfers to reconcile its accounting
+  // with that of the exchange. Used by
+  // taler-merchant-wirewatch.
+  credit_facade_url?: string;
+
+  // Credentials for accessing the credit facade.
+  credit_facade_credentials?: FacadeCredentials;
+}
+
+export interface MerchantInstanceConfig {
+  accounts: MerchantBankAccount[];
+  auth: MerchantAuthConfiguration;
+  id: string;
+  name: string;
+  address: unknown;
+  jurisdiction: unknown;
+  use_stefan: boolean;
+  default_wire_transfer_delay: TalerProtocolDuration;
+  default_pay_delay: TalerProtocolDuration;
+}
+
+export interface PrivateOrderStatusQuery {
+  instance?: string;
+  orderId: string;
+  sessionId?: string;
+}
+
+/**
+ * Client for the GNU Taler merchant backend.
+ */
+export class MerchantApiClient {
+  /**
+   * Base URL for the particular instance that this merchant API client
+   * is for.
+   */
+  private baseUrl: string;
+
+  readonly auth: MerchantAuthConfiguration;
+
+  constructor(baseUrl: string, auth?: MerchantAuthConfiguration) {
+    this.baseUrl = baseUrl;
+
+    this.auth = auth ?? {
+      method: "external",
+    };
+  }
+
+  httpClient = createPlatformHttpLib({
+    allowHttp: true,
+    enableThrottling: false,
+  });
+
+  async changeAuth(auth: MerchantAuthConfiguration): Promise<void> {
+    const url = new URL("private/auth", this.baseUrl);
+    const res = await this.httpClient.fetch(url.href, {
+      method: "POST",
+      body: auth,
+      headers: this.makeAuthHeader(),
+    });
+    await expectSuccessResponseOrThrow(res);
+  }
+
+  async deleteTippingReserve(req: DeleteTippingReserveArgs): Promise<void> {
+    const url = new URL(`private/reserves/${req.reservePub}`, this.baseUrl);
+    if (req.purge) {
+      url.searchParams.set("purge", "YES");
+    }
+    const resp = await this.httpClient.fetch(url.href, {
+      method: "DELETE",
+      headers: this.makeAuthHeader(),
+    });
+    logger.info(`delete status: ${resp.status}`);
+    return;
+  }
+
+  async createTippingReserve(
+    req: CreateMerchantTippingReserveRequest,
+  ): Promise<MerchantReserveCreateConfirmation> {
+    const url = new URL("private/reserves", this.baseUrl);
+    const resp = await this.httpClient.fetch(url.href, {
+      method: "POST",
+      body: req,
+      headers: this.makeAuthHeader(),
+    });
+    const respData = readSuccessResponseJsonOrThrow(
+      resp,
+      codecForMerchantReserveCreateConfirmation(),
+    );
+    return respData;
+  }
+
+  async getPrivateInstanceInfo(): Promise<any> {
+    const url = new URL("private", this.baseUrl);
+    const resp = await this.httpClient.fetch(url.href, {
+      method: "GET",
+      headers: this.makeAuthHeader(),
+    });
+    return await resp.json();
+  }
+
+  async getPrivateTipReserves(): Promise<TippingReserveStatus> {
+    const url = new URL("private/reserves", this.baseUrl);
+    const resp = await this.httpClient.fetch(url.href, {
+      method: "GET",
+      headers: this.makeAuthHeader(),
+    });
+    // FIXME: Validate!
+    return await resp.json();
+  }
+
+  async deleteInstance(instanceId: string) {
+    const url = new URL(`management/instances/${instanceId}`, this.baseUrl);
+    const resp = await this.httpClient.fetch(url.href, {
+      method: "DELETE",
+      headers: this.makeAuthHeader(),
+    });
+    await expectSuccessResponseOrThrow(resp);
+  }
+
+  async createInstance(req: MerchantInstanceConfig): Promise<void> {
+    const url = new URL("management/instances", this.baseUrl);
+    await this.httpClient.fetch(url.href, {
+      method: "POST",
+      body: req,
+      headers: this.makeAuthHeader(),
+    });
+  }
+
+  async getInstances(): Promise<MerchantInstancesResponse> {
+    const url = new URL("management/instances", this.baseUrl);
+    const resp = await this.httpClient.fetch(url.href, {
+      headers: this.makeAuthHeader(),
+    });
+    return resp.json();
+  }
+
+  async getInstanceFullDetails(instanceId: string): Promise<any> {
+    const url = new URL(`management/instances/${instanceId}`, this.baseUrl);
+    try {
+      const resp = await this.httpClient.fetch(url.href, {
+        headers: this.makeAuthHeader(),
+      });
+      return resp.json();
+    } catch (e) {
+      throw e;
+    }
+  }
+
+  async createOrder(
+    req: MerchantPostOrderRequest,
+  ): Promise<MerchantPostOrderResponse> {
+    let url = new URL("private/orders", this.baseUrl);
+    const resp = await this.httpClient.fetch(url.href, {
+      method: "POST",
+      body: req,
+      headers: this.makeAuthHeader(),
+    });
+    return readSuccessResponseJsonOrThrow(
+      resp,
+      codecForMerchantPostOrderResponse(),
+    );
+  }
+
+  async queryPrivateOrderStatus(
+    query: PrivateOrderStatusQuery,
+  ): Promise<MerchantOrderPrivateStatusResponse> {
+    const reqUrl = new URL(`private/orders/${query.orderId}`, this.baseUrl);
+    if (query.sessionId) {
+      reqUrl.searchParams.set("session_id", query.sessionId);
+    }
+    const resp = await this.httpClient.fetch(reqUrl.href, {
+      headers: this.makeAuthHeader(),
+    });
+    return readSuccessResponseJsonOrThrow(
+      resp,
+      codecForMerchantOrderPrivateStatusResponse(),
+    );
+  }
+
+  async giveTip(req: RewardCreateRequest): Promise<RewardCreateConfirmation> {
+    const reqUrl = new URL(`private/tips`, this.baseUrl);
+    const resp = await this.httpClient.fetch(reqUrl.href, {
+      method: "POST",
+      body: req,
+    });
+    // FIXME: validate
+    return resp.json();
+  }
+
+  async queryTippingReserves(): Promise<TippingReserveStatus> {
+    const reqUrl = new URL(`private/reserves`, this.baseUrl);
+    const resp = await this.httpClient.fetch(reqUrl.href, {
+      headers: this.makeAuthHeader(),
+    });
+    // FIXME: validate
+    return resp.json();
+  }
+
+  async giveRefund(r: {
+    instance: string;
+    orderId: string;
+    amount: string;
+    justification: string;
+  }): Promise<{ talerRefundUri: string }> {
+    const reqUrl = new URL(`private/orders/${r.orderId}/refund`, this.baseUrl);
+    const resp = await this.httpClient.fetch(reqUrl.href, {
+      method: "POST",
+      body: {
+        refund: r.amount,
+        reason: r.justification,
+      },
+    });
+    const respBody = await resp.json();
+    return {
+      talerRefundUri: respBody.taler_refund_uri,
+    };
+  }
+
+  async createTemplate(req: MerchantTemplateAddDetails) {
+    let url = new URL("private/templates", this.baseUrl);
+    const resp = await this.httpClient.fetch(url.href, {
+      method: "POST",
+      body: req,
+      headers: this.makeAuthHeader(),
+    });
+    if (resp.status !== 204) {
+      throw Error("failed to create template");
+    }
+  }
+
+  private makeAuthHeader(): Record<string, string> {
+    switch (this.auth.method) {
+      case "external":
+        return {};
+      case "token":
+        return {
+          Authorization: `Bearer ${this.auth.token}`,
+        };
+    }
+  }
+}
diff --git a/packages/taler-util/src/libeufin-api-types.ts 
b/packages/taler-util/src/libeufin-api-types.ts
new file mode 100644
index 000000000..aa3d0cb7a
--- /dev/null
+++ b/packages/taler-util/src/libeufin-api-types.ts
@@ -0,0 +1,31 @@
+/*
+ This file is part of GNU Taler
+ (C) 2023 Taler Systems S.A.
+
+ GNU 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.
+
+ GNU 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
+ GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+
+export type FacadeCredentials =
+  | NoFacadeCredentials
+  | BasicAuthFacadeCredentials;
+export interface NoFacadeCredentials {
+  type: "none";
+}
+export interface BasicAuthFacadeCredentials {
+  type: "basic";
+
+  // Username to use to authenticate
+  username: string;
+
+  // Password to use to authenticate
+  password: string;
+}

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]