gnunet-svn
[Top][All Lists]
Advanced

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

[taler-wallet-core] branch master updated: store 'list issue date' of de


From: gnunet
Subject: [taler-wallet-core] branch master updated: store 'list issue date' of denoms, cleanup
Date: Thu, 19 Aug 2021 13:48:48 +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 3ce740d8 store 'list issue date' of denoms, cleanup
3ce740d8 is described below

commit 3ce740d87dc51c2f9a330d3e12237ba1fdd5f2e7
Author: Florian Dold <florian@dold.me>
AuthorDate: Thu Aug 19 13:48:36 2021 +0200

    store 'list issue date' of denoms, cleanup
---
 packages/taler-util/src/backupTypes.ts             |   6 +
 packages/taler-wallet-cli/src/index.ts             |  13 +-
 .../src/integrationtests/test-pay-paid.ts          |   4 +-
 .../src/integrationtests/test-payment-on-demo.ts   |   4 +-
 .../src/integrationtests/test-payment-transient.ts |   5 +-
 .../src/integrationtests/testrunner.ts             |   9 +
 packages/taler-wallet-core/src/db.ts               | 204 +++++----------------
 packages/taler-wallet-core/src/headless/helpers.ts |   3 +-
 packages/taler-wallet-core/src/index.ts            |   3 +-
 .../src/operations/backup/export.ts                |   1 +
 .../src/operations/backup/import.ts                |   1 +
 .../taler-wallet-core/src/operations/exchanges.ts  |   4 +-
 .../src/operations/withdraw.test.ts                |   6 +
 .../taler-wallet-webextension/src/wxBackend.ts     |   1 -
 14 files changed, 87 insertions(+), 177 deletions(-)

diff --git a/packages/taler-util/src/backupTypes.ts 
b/packages/taler-util/src/backupTypes.ts
index 97fbcebc..70e52e63 100644
--- a/packages/taler-util/src/backupTypes.ts
+++ b/packages/taler-util/src/backupTypes.ts
@@ -897,6 +897,12 @@ export interface BackupDenomination {
    * Coins of this denomination.
    */
   coins: BackupCoin[];
+
+  /**
+   * The list issue date of the exchange "/keys" response
+   * that this denomination was last seen in.
+   */
+  list_issue_date: Timestamp;
 }
 
 /**
diff --git a/packages/taler-wallet-cli/src/index.ts 
b/packages/taler-wallet-cli/src/index.ts
index 673bfab2..796b6ae1 100644
--- a/packages/taler-wallet-cli/src/index.ts
+++ b/packages/taler-wallet-cli/src/index.ts
@@ -901,12 +901,12 @@ deploymentCli
   .action(async (args) => {
     let out = "";
 
-    const stamp = Math.floor((new Date()).getTime() / 1000);
+    const stamp = Math.floor(new Date().getTime() / 1000);
 
     const min = Amounts.parseOrThrow(args.coincfg.minAmount);
     const max = Amounts.parseOrThrow(args.coincfg.maxAmount);
     if (min.currency != max.currency) {
-      console.error("currency mismatch")
+      console.error("currency mismatch");
       process.exit(1);
     }
     const currency = min.currency;
@@ -961,7 +961,14 @@ testCli
   .subcommand("listIntegrationtests", "list-integrationtests")
   .action(async (args) => {
     for (const t of getTestInfo()) {
-      console.log(t.name);
+      let s = t.name;
+      if (t.suites.length > 0) {
+        s += ` (suites: ${t.suites.join(",")})`;
+      }
+      if (t.excludeByDefault) {
+        s += ` [excluded by default]`;
+      }
+      console.log(s);
     }
   });
 
diff --git a/packages/taler-wallet-cli/src/integrationtests/test-pay-paid.ts 
b/packages/taler-wallet-cli/src/integrationtests/test-pay-paid.ts
index bf8ed7a3..64645dce 100644
--- a/packages/taler-wallet-cli/src/integrationtests/test-pay-paid.ts
+++ b/packages/taler-wallet-cli/src/integrationtests/test-pay-paid.ts
@@ -145,10 +145,10 @@ export async function runPayPaidTest(t: GlobalTestState) {
 
   console.log(publicOrderStatusResp.data);
 
-  if (publicOrderStatusResp.status != 202) {
+  if (publicOrderStatusResp.status != 200) {
     console.log(publicOrderStatusResp.data);
     throw Error(
-      `expected status 202 (after paying), but got 
${publicOrderStatusResp.status}`,
+      `expected status 200 (after paying), but got 
${publicOrderStatusResp.status}`,
     );
   }
 
diff --git 
a/packages/taler-wallet-cli/src/integrationtests/test-payment-on-demo.ts 
b/packages/taler-wallet-cli/src/integrationtests/test-payment-on-demo.ts
index d490a8c1..0dabc9ca 100644
--- a/packages/taler-wallet-cli/src/integrationtests/test-payment-on-demo.ts
+++ b/packages/taler-wallet-cli/src/integrationtests/test-payment-on-demo.ts
@@ -24,8 +24,6 @@ import {
   BankAccessApi
 } from "./harness";
 import {
-  createSimpleTestkudosEnvironment,
-  withdrawViaBank,
   makeTestPayment,
 } from "./helpers";
 import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
@@ -96,4 +94,6 @@ export async function runPaymentDemoTest(t: GlobalTestState) {
   t.assertTrue(balanceAfter["balances"].length == 1);
   t.assertTrue(balanceBefore["balances"][0]["available"] > 
balanceAfter["balances"][0]["available"]);
 }
+
+runPaymentDemoTest.excludeByDefault = true;
 runPaymentDemoTest.suites = ["buildbot"];
diff --git 
a/packages/taler-wallet-cli/src/integrationtests/test-payment-transient.ts 
b/packages/taler-wallet-cli/src/integrationtests/test-payment-transient.ts
index 2c417e71..b171ff66 100644
--- a/packages/taler-wallet-cli/src/integrationtests/test-payment-transient.ts
+++ b/packages/taler-wallet-cli/src/integrationtests/test-payment-transient.ts
@@ -169,16 +169,17 @@ export async function runPaymentTransientTest(t: 
GlobalTestState) {
 
   // Now ask the merchant if paid
 
+  console.log("requesting", publicOrderStatusUrl);
   publicOrderStatusResp = await axios.get(publicOrderStatusUrl, {
     validateStatus: () => true,
   });
 
   console.log(publicOrderStatusResp.data);
 
-  if (publicOrderStatusResp.status != 202) {
+  if (publicOrderStatusResp.status != 200) {
     console.log(publicOrderStatusResp.data);
     throw Error(
-      `expected status 202 (after paying), but got 
${publicOrderStatusResp.status}`,
+      `expected status 200 (after paying), but got 
${publicOrderStatusResp.status}`,
     );
   }
 }
diff --git a/packages/taler-wallet-cli/src/integrationtests/testrunner.ts 
b/packages/taler-wallet-cli/src/integrationtests/testrunner.ts
index cb1d621b..1c090881 100644
--- a/packages/taler-wallet-cli/src/integrationtests/testrunner.ts
+++ b/packages/taler-wallet-cli/src/integrationtests/testrunner.ts
@@ -90,6 +90,7 @@ import { runMerchantSpecPublicOrdersTest } from 
"./test-merchant-spec-public-ord
 interface TestMainFunction {
   (t: GlobalTestState): Promise<void>;
   timeoutMs?: number;
+  excludeByDefault?: boolean;
   suites?: string[];
 }
 
@@ -157,6 +158,8 @@ export interface TestRunSpec {
 
 export interface TestInfo {
   name: string;
+  suites: string[];
+  excludeByDefault: boolean;
 }
 
 function updateCurrentSymlink(testDir: string): void {
@@ -236,6 +239,10 @@ export async function runTests(spec: TestRunSpec) {
       if (intersection.size === 0) {
         continue;
       }
+    } else {
+      if (testCase.excludeByDefault) {
+        continue;
+      }
     }
 
     if (spec.dryRun) {
@@ -389,6 +396,8 @@ export function reportAndQuit(
 export function getTestInfo(): TestInfo[] {
   return allTests.map((x) => ({
     name: getTestName(x),
+    suites: x.suites ?? [],
+    excludeByDefault: x.excludeByDefault ?? false,
   }));
 }
 
diff --git a/packages/taler-wallet-core/src/db.ts 
b/packages/taler-wallet-core/src/db.ts
index 437d2e7b..65a874ea 100644
--- a/packages/taler-wallet-core/src/db.ts
+++ b/packages/taler-wallet-core/src/db.ts
@@ -18,17 +18,10 @@
  * Imports.
  */
 import {
-  openDatabase,
   describeStore,
   describeContents,
   describeIndex,
-  DbAccess,
-  StoreDescriptor,
-  StoreWithIndexes,
-  IndexDescriptor,
 } from "./util/query.js";
-import { IDBFactory, IDBDatabase, IDBTransaction } from 
"@gnu-taler/idb-bridge";
-import { Logger } from "@gnu-taler/taler-util";
 import {
   AmountJson,
   AmountString,
@@ -53,11 +46,17 @@ import { PayCoinSelection } from "./util/coinSelection.js";
  * for all previous versions must be written, which should be
  * avoided.
  */
-const TALER_DB_NAME = "taler-wallet-main-v2";
+export const TALER_DB_NAME = "taler-wallet-main-v2";
 
-const TALER_META_DB_NAME = "taler-wallet-meta";
+/**
+ * Name of the metadata database.  This database is used
+ * to track major migrations of the main Taler database.
+ *
+ * (Minor migrations are handled via upgrade transactions.)
+ */
+export const TALER_META_DB_NAME = "taler-wallet-meta";
 
-const CURRENT_DB_CONFIG_KEY = "currentMainDbName";
+export const CURRENT_DB_CONFIG_KEY = "currentMainDbName";
 
 /**
  * Current database minor version, should be incremented
@@ -68,124 +67,6 @@ const CURRENT_DB_CONFIG_KEY = "currentMainDbName";
  */
 export const WALLET_DB_MINOR_VERSION = 1;
 
-const logger = new Logger("db.ts");
-
-function upgradeFromStoreMap(
-  storeMap: any,
-  db: IDBDatabase,
-  oldVersion: number,
-  newVersion: number,
-  upgradeTransaction: IDBTransaction,
-): void {
-  if (oldVersion === 0) {
-    for (const n in storeMap) {
-      const swi: StoreWithIndexes<StoreDescriptor<unknown>, any> = storeMap[n];
-      const storeDesc: StoreDescriptor<unknown> = swi.store;
-      const s = db.createObjectStore(storeDesc.name, {
-        autoIncrement: storeDesc.autoIncrement,
-        keyPath: storeDesc.keyPath,
-      });
-      for (const indexName in swi.indexMap as any) {
-        const indexDesc: IndexDescriptor = swi.indexMap[indexName];
-        s.createIndex(indexDesc.name, indexDesc.keyPath, {
-          multiEntry: indexDesc.multiEntry,
-        });
-      }
-    }
-    return;
-  }
-  if (oldVersion === newVersion) {
-    return;
-  }
-  logger.info(`upgrading database from ${oldVersion} to ${newVersion}`);
-  throw Error("upgrade not supported");
-}
-
-function onTalerDbUpgradeNeeded(
-  db: IDBDatabase,
-  oldVersion: number,
-  newVersion: number,
-  upgradeTransaction: IDBTransaction,
-) {
-  upgradeFromStoreMap(
-    WalletStoresV1,
-    db,
-    oldVersion,
-    newVersion,
-    upgradeTransaction,
-  );
-}
-
-function onMetaDbUpgradeNeeded(
-  db: IDBDatabase,
-  oldVersion: number,
-  newVersion: number,
-  upgradeTransaction: IDBTransaction,
-) {
-  upgradeFromStoreMap(
-    walletMetadataStore,
-    db,
-    oldVersion,
-    newVersion,
-    upgradeTransaction,
-  );
-}
-
-/**
- * Return a promise that resolves
- * to the taler wallet db.
- */
-export async function openTalerDatabase(
-  idbFactory: IDBFactory,
-  onVersionChange: () => void,
-): Promise<DbAccess<typeof WalletStoresV1>> {
-  const metaDbHandle = await openDatabase(
-    idbFactory,
-    TALER_META_DB_NAME,
-    1,
-    () => {},
-    onMetaDbUpgradeNeeded,
-  );
-
-  const metaDb = new DbAccess(metaDbHandle, walletMetadataStore);
-  let currentMainVersion: string | undefined;
-  await metaDb
-    .mktx((x) => ({
-      metaConfig: x.metaConfig,
-    }))
-    .runReadWrite(async (tx) => {
-      const dbVersionRecord = await tx.metaConfig.get(CURRENT_DB_CONFIG_KEY);
-      if (!dbVersionRecord) {
-        currentMainVersion = TALER_DB_NAME;
-        await tx.metaConfig.put({
-          key: CURRENT_DB_CONFIG_KEY,
-          value: TALER_DB_NAME,
-        });
-      } else {
-        currentMainVersion = dbVersionRecord.value;
-      }
-    });
-
-  if (currentMainVersion !== TALER_DB_NAME) {
-    // In the future, the migration logic will be implemented here.
-    throw Error(`migration from database ${currentMainVersion} not supported`);
-  }
-
-  const mainDbHandle = await openDatabase(
-    idbFactory,
-    TALER_DB_NAME,
-    WALLET_DB_MINOR_VERSION,
-    onVersionChange,
-    onTalerDbUpgradeNeeded,
-  );
-
-  return new DbAccess(mainDbHandle, WalletStoresV1);
-}
-
-export function deleteTalerDatabase(idbFactory: IDBFactory): void {
-  idbFactory.deleteDatabase(TALER_DB_NAME);
-}
-
 export enum ReserveRecordStatus {
   /**
    * Reserve must be registered with the bank.
@@ -217,6 +98,10 @@ export enum ReserveRecordStatus {
   BANK_ABORTED = "bank-aborted",
 }
 
+/**
+ * Extra info about a reserve that is used
+ * with a bank-integrated withdrawal.
+ */
 export interface ReserveBankInfo {
   /**
    * Status URL that the wallet will use to query the status
@@ -224,6 +109,10 @@ export interface ReserveBankInfo {
    */
   statusUrl: string;
 
+  /**
+   * URL that the user can be redirected to, and allows
+   * them to confirm (or abort) the bank-integrated withdrawal.
+   */
   confirmUrl?: string;
 
   /**
@@ -339,25 +228,9 @@ export interface ReserveRecord {
 }
 
 /**
- * Auditor record as stored with currencies in the exchange database.
+ * Record that indicates the wallet trusts
+ * a particular auditor.
  */
-export interface AuditorRecord {
-  /**
-   * Base url of the auditor.
-   */
-  baseUrl: string;
-
-  /**
-   * Public signing key of the auditor.
-   */
-  auditorPub: string;
-
-  /**
-   * Time when the auditing expires.
-   */
-  expirationStamp: number;
-}
-
 export interface AuditorTrustRecord {
   /**
    * Currency that we trust this auditor for.
@@ -381,6 +254,9 @@ export interface AuditorTrustRecord {
   uids: string[];
 }
 
+/**
+ * Record to indicate trust for a particular exchange.
+ */
 export interface ExchangeTrustRecord {
   /**
    * Currency that we trust this exchange for.
@@ -519,8 +395,17 @@ export interface DenominationRecord {
    * on the denomination.
    */
   exchangeMasterPub: string;
+
+  /**
+   * Latest list issue date of the "/keys" response
+   * that includes this denomination.
+   */
+  listIssueDate: Timestamp;
 }
 
+/**
+ * Information about one of the exchange's bank accounts.
+ */
 export interface ExchangeBankAccount {
   payto_uri: string;
   master_sig: string;
@@ -554,6 +439,8 @@ export interface ExchangeDetailsRecord {
   /**
    * Signing keys we got from the exchange, can also contain
    * older signing keys that are not returned by /keys anymore.
+   *
+   * FIXME:  Should this be put into a separate object store?
    */
   signingKeys: ExchangeSignKeyJson[];
 
@@ -610,6 +497,9 @@ export interface ExchangeRecord {
    */
   baseUrl: string;
 
+  /**
+   * Pointer to the current exchange details.
+   */
   detailsPointer: ExchangeDetailsPointer | undefined;
 
   /**
@@ -701,7 +591,9 @@ export interface PlanchetRecord {
 }
 
 /**
- * Planchet for a coin during refrehs.
+ * Planchet for a coin during refresh.
+ *
+ * FIXME:  Not used in DB?
  */
 export interface RefreshPlanchet {
   /**
@@ -1040,6 +932,8 @@ export interface RefreshGroupRecord {
 
   oldCoinPubs: string[];
 
+  // FIXME:  Should this go into a separate
+  // object store for faster updates?
   refreshSessionPerCoin: (RefreshSessionRecord | undefined)[];
 
   inputPerCoin: AmountJson[];
@@ -1126,21 +1020,6 @@ export interface WireFee {
   sig: string;
 }
 
-/**
- * Record to store information about a refund event.
- *
- * All information about a refund is stored with the purchase,
- * this event is just for the history.
- *
- * The event is only present for completed refunds.
- */
-export interface RefundEventRecord {
-  timestamp: Timestamp;
-  merchantExecutionTimestamp: Timestamp;
-  refundGroupId: string;
-  proposalId: string;
-}
-
 export enum RefundState {
   Failed = "failed",
   Applied = "applied",
@@ -1381,7 +1260,6 @@ export const WALLET_BACKUP_STATE_KEY = 
"walletBackupState";
 /**
  * Configuration key/value entries to configure
  * the wallet.
- *
  */
 export type ConfigRecord =
   | {
diff --git a/packages/taler-wallet-core/src/headless/helpers.ts 
b/packages/taler-wallet-core/src/headless/helpers.ts
index f29dfd69..a862dab4 100644
--- a/packages/taler-wallet-core/src/headless/helpers.ts
+++ b/packages/taler-wallet-core/src/headless/helpers.ts
@@ -27,7 +27,7 @@ import {
   BridgeIDBFactory,
   shimIndexedDB,
 } from "@gnu-taler/idb-bridge";
-import { openTalerDatabase } from "../db.js";
+import { openTalerDatabase } from "../db-utils.js";
 import { HttpRequestLibrary } from "../util/http.js";
 import { NodeThreadCryptoWorkerFactory } from 
"../crypto/workers/nodeThreadWorker.js";
 import { NodeHttpLib } from "./NodeHttpLib.js";
@@ -35,7 +35,6 @@ import { Logger } from "@gnu-taler/taler-util";
 import { SynchronousCryptoWorkerFactory } from 
"../crypto/workers/synchronousWorker.js";
 import type { IDBFactory } from "@gnu-taler/idb-bridge";
 import { WalletNotification } from "@gnu-taler/taler-util";
-import { InternalWalletState } from "../common.js";
 import { Wallet } from "../wallet.js";
 
 const logger = new Logger("headless/helpers.ts");
diff --git a/packages/taler-wallet-core/src/index.ts 
b/packages/taler-wallet-core/src/index.ts
index a1489474..ccd3488d 100644
--- a/packages/taler-wallet-core/src/index.ts
+++ b/packages/taler-wallet-core/src/index.ts
@@ -29,6 +29,7 @@ export * from "./util/http.js";
 export * from "./versions.js";
 
 export * from "./db.js";
+export * from "./db-utils.js";
 
 // Crypto and crypto workers
 // export * from "./crypto/workers/nodeThreadWorker.js";
@@ -44,4 +45,4 @@ export { InternalWalletState } from "./common.js";
 export * from "./wallet-api-types.js";
 export * from "./wallet.js";
 
-export * from "./operations/backup/index.js"
\ No newline at end of file
+export * from "./operations/backup/index.js";
diff --git a/packages/taler-wallet-core/src/operations/backup/export.ts 
b/packages/taler-wallet-core/src/operations/backup/export.ts
index eae7995c..4d9ca669 100644
--- a/packages/taler-wallet-core/src/operations/backup/export.ts
+++ b/packages/taler-wallet-core/src/operations/backup/export.ts
@@ -260,6 +260,7 @@ export async function exportBackup(
           stamp_expire_withdraw: denom.stampExpireWithdraw,
           stamp_start: denom.stampStart,
           value: Amounts.stringify(denom.value),
+          list_issue_date: denom.listIssueDate,
         });
       });
 
diff --git a/packages/taler-wallet-core/src/operations/backup/import.ts 
b/packages/taler-wallet-core/src/operations/backup/import.ts
index e2064a80..8ba4e4db 100644
--- a/packages/taler-wallet-core/src/operations/backup/import.ts
+++ b/packages/taler-wallet-core/src/operations/backup/import.ts
@@ -360,6 +360,7 @@ export async function importBackup(
               stampStart: backupDenomination.stamp_start,
               status: DenominationStatus.VerifiedGood,
               value: Amounts.parseOrThrow(backupDenomination.value),
+              listIssueDate: backupDenomination.list_issue_date,
             });
           }
           for (const backupCoin of backupDenomination.coins) {
diff --git a/packages/taler-wallet-core/src/operations/exchanges.ts 
b/packages/taler-wallet-core/src/operations/exchanges.ts
index 64821a7b..0670c8a6 100644
--- a/packages/taler-wallet-core/src/operations/exchanges.ts
+++ b/packages/taler-wallet-core/src/operations/exchanges.ts
@@ -31,7 +31,6 @@ import {
   ExchangeWireJson,
   getTimestampNow,
   isTimestampExpired,
-  j2s,
   Logger,
   NotificationType,
   parsePaytoUri,
@@ -76,6 +75,7 @@ const logger = new Logger("exchanges.ts");
 function denominationRecordFromKeys(
   exchangeBaseUrl: string,
   exchangeMasterPub: string,
+  listIssueDate: Timestamp,
   denomIn: Denomination,
 ): DenominationRecord {
   const denomPubHash = encodeCrock(hash(decodeCrock(denomIn.denom_pub)));
@@ -97,6 +97,7 @@ function denominationRecordFromKeys(
     stampStart: denomIn.stamp_start,
     status: DenominationStatus.Unverified,
     value: Amounts.parseOrThrow(denomIn.value),
+    listIssueDate,
   };
   return d;
 }
@@ -380,6 +381,7 @@ async function downloadKeysInfo(
       denominationRecordFromKeys(
         baseUrl,
         exchangeKeysJson.master_public_key,
+        exchangeKeysJson.list_issue_date,
         d,
       ),
     ),
diff --git a/packages/taler-wallet-core/src/operations/withdraw.test.ts 
b/packages/taler-wallet-core/src/operations/withdraw.test.ts
index c6de0a32..061a4222 100644
--- a/packages/taler-wallet-core/src/operations/withdraw.test.ts
+++ b/packages/taler-wallet-core/src/operations/withdraw.test.ts
@@ -76,6 +76,7 @@ test("withdrawal selection bug repro", (t) => {
         fraction: 0,
         value: 1000,
       },
+      listIssueDate: { t_ms: 0 },
     },
     {
       denomPub:
@@ -126,6 +127,7 @@ test("withdrawal selection bug repro", (t) => {
         fraction: 0,
         value: 10,
       },
+      listIssueDate: { t_ms: 0 },
     },
     {
       denomPub:
@@ -176,6 +178,7 @@ test("withdrawal selection bug repro", (t) => {
         fraction: 0,
         value: 5,
       },
+      listIssueDate: { t_ms: 0 },
     },
     {
       denomPub:
@@ -226,6 +229,7 @@ test("withdrawal selection bug repro", (t) => {
         fraction: 0,
         value: 1,
       },
+      listIssueDate: { t_ms: 0 },
     },
     {
       denomPub:
@@ -276,6 +280,7 @@ test("withdrawal selection bug repro", (t) => {
         fraction: 10000000,
         value: 0,
       },
+      listIssueDate: { t_ms: 0 },
     },
     {
       denomPub:
@@ -326,6 +331,7 @@ test("withdrawal selection bug repro", (t) => {
         fraction: 0,
         value: 2,
       },
+      listIssueDate: { t_ms: 0 },
     },
   ];
 
diff --git a/packages/taler-wallet-webextension/src/wxBackend.ts 
b/packages/taler-wallet-webextension/src/wxBackend.ts
index c474c940..c41dd4fb 100644
--- a/packages/taler-wallet-webextension/src/wxBackend.ts
+++ b/packages/taler-wallet-webextension/src/wxBackend.ts
@@ -34,7 +34,6 @@ import {
   DbAccess,
   WalletStoresV1,
   Wallet,
-  WalletApiOperation,
 } from "@gnu-taler/taler-wallet-core";
 import {
   classifyTalerUri,

-- 
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]