diff options
Diffstat (limited to 'packages/taler-harness')
| -rw-r--r-- | packages/taler-harness/src/integrationtests/test-exchange-purse.ts | 224 | ||||
| -rw-r--r-- | packages/taler-harness/src/integrationtests/testrunner.ts | 9 | 
2 files changed, 232 insertions, 1 deletions
| diff --git a/packages/taler-harness/src/integrationtests/test-exchange-purse.ts b/packages/taler-harness/src/integrationtests/test-exchange-purse.ts new file mode 100644 index 000000000..5a1d02692 --- /dev/null +++ b/packages/taler-harness/src/integrationtests/test-exchange-purse.ts @@ -0,0 +1,224 @@ +/* + 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/> + */ + +/** + * Imports. + */ +import { +  AbsoluteTime, +  ContractTermsUtil, +  decodeCrock, +  Duration, +  encodeCrock, +  getRandomBytes, +  hash, +  j2s, +  PeerContractTerms, +  TalerError, +  TalerPreciseTimestamp, +} from "@gnu-taler/taler-util"; +import { +  checkReserve, +  CryptoDispatcher, +  downloadExchangeInfo, +  EncryptContractRequest, +  findDenomOrThrow, +  SpendCoinDetails, +  SynchronousCryptoWorkerFactoryPlain, +  topupReserveWithDemobank, +  Wallet, +  withdrawCoin, +} from "@gnu-taler/taler-wallet-core"; +import { GlobalTestState, harnessHttpLib } from "../harness/harness.js"; +import { createSimpleTestkudosEnvironmentV2 } from "../harness/helpers.js"; + +/** + * Test the exchange's purse API. + */ +export async function runExchangePurseTest(t: GlobalTestState) { +  // Set up test environment + +  const { bank, exchange } = await createSimpleTestkudosEnvironmentV2(t); + +  const http = harnessHttpLib; +  const cryptoDisp = new CryptoDispatcher( +    new SynchronousCryptoWorkerFactoryPlain(), +  ); +  const cryptoApi = cryptoDisp.cryptoApi; + +  try { +    // Withdraw digital cash into the wallet. + +    const exchangeInfo = await downloadExchangeInfo(exchange.baseUrl, http); + +    const reserveKeyPair = await cryptoApi.createEddsaKeypair({}); + +    let reserveUrl = new URL( +      `reserves/${reserveKeyPair.pub}`, +      exchange.baseUrl, +    ); +    reserveUrl.searchParams.set("timeout_ms", "30000"); +    const longpollReq = http.fetch(reserveUrl.href, { +      method: "GET", +    }); + +    await topupReserveWithDemobank({ +      amount: "TESTKUDOS:10", +      http, +      reservePub: reserveKeyPair.pub, +      bankAccessApiBaseUrl: bank.bankAccessApiBaseUrl, +      exchangeInfo, +    }); + +    console.log("waiting for longpoll request"); +    const resp = await longpollReq; +    console.log(`got response, status ${resp.status}`); + +    console.log(exchangeInfo); + +    await checkReserve(http, exchange.baseUrl, reserveKeyPair.pub); + +    const d1 = findDenomOrThrow(exchangeInfo, "TESTKUDOS:8", { +      denomselAllowLate: Wallet.defaultConfig.testing.denomselAllowLate, +    }); + +    const coin = await withdrawCoin({ +      http, +      cryptoApi, +      reserveKeyPair: { +        reservePriv: reserveKeyPair.priv, +        reservePub: reserveKeyPair.pub, +      }, +      denom: d1, +      exchangeBaseUrl: exchange.baseUrl, +    }); + +    const amount = "TESTKUDOS:5"; +    const purseFee = "TESTKUDOS:0"; + +    const mergeTimestamp = TalerPreciseTimestamp.now(); + +    const contractTerms: PeerContractTerms = { +      amount, +      summary: "Hello", +      purse_expiration: AbsoluteTime.toProtocolTimestamp( +        AbsoluteTime.addDuration( +          AbsoluteTime.now(), +          Duration.fromSpec({ minutes: 1 }), +        ), +      ), +    }; + +    const mergeReservePair = await cryptoApi.createEddsaKeypair({}); +    const pursePair = await cryptoApi.createEddsaKeypair({}); +    const mergePair = await cryptoApi.createEddsaKeypair({}); +    const contractPair = await cryptoApi.createEddsaKeypair({}); +    const contractEncNonce = encodeCrock(getRandomBytes(24)); + +    const pursePub = pursePair.pub; + +    const hContractTerms = ContractTermsUtil.hashContractTerms(contractTerms); + +    const purseSigResp = await cryptoApi.signPurseCreation({ +      hContractTerms, +      mergePub: mergePair.pub, +      minAge: 0, +      purseAmount: amount, +      purseExpiration: contractTerms.purse_expiration, +      pursePriv: pursePair.priv, +    }); + +    const coinSpend: SpendCoinDetails = { +      ageCommitmentProof: undefined, +      coinPriv: coin.coinPriv, +      coinPub: coin.coinPub, +      contribution: amount, +      denomPubHash: coin.denomPubHash, +      denomSig: coin.denomSig, +    }; + +    const depositSigsResp = await cryptoApi.signPurseDeposits({ +      exchangeBaseUrl: exchange.baseUrl, +      pursePub: pursePair.pub, +      coins: [coinSpend], +    }); + +    const encryptContractRequest: EncryptContractRequest = { +      contractTerms: contractTerms, +      mergePriv: mergePair.priv, +      pursePriv: pursePair.priv, +      pursePub: pursePair.pub, +      contractPriv: contractPair.priv, +      contractPub: contractPair.pub, +      nonce: contractEncNonce, +    }; + +    const econtractResp = await cryptoApi.encryptContractForMerge( +      encryptContractRequest, +    ); + +    const econtractHash = encodeCrock( +      hash(decodeCrock(econtractResp.econtract.econtract)), +    ); + +    const createPurseUrl = new URL( +      `purses/${pursePair.pub}/create`, +      exchange.baseUrl, +    ); + +    const reqBody = { +      amount: amount, +      merge_pub: mergePair.pub, +      purse_sig: purseSigResp.sig, +      h_contract_terms: hContractTerms, +      purse_expiration: contractTerms.purse_expiration, +      deposits: depositSigsResp.deposits, +      min_age: 0, +      econtract: econtractResp.econtract, +    }; + +    const httpResp = await http.fetch(createPurseUrl.href, { +      method: "POST", +      body: reqBody, +    }); + +    const respBody = await httpResp.json(); + +    console.log("status", httpResp.status); + +    console.log(j2s(respBody)); + +    const mergeUrl = new URL(`purses/${pursePub}/merge`, exchange.baseUrl); +    mergeUrl.searchParams.set("timeout_ms", "300"); +    const statusResp = await http.fetch(mergeUrl.href, {}); + +    const statusRespBody = await statusResp.json(); + +    console.log(j2s(statusRespBody)); + +    t.assertTrue(statusRespBody.merge_timestamp === undefined); +  } catch (e) { +    if (e instanceof TalerError) { +      console.log(e); +      console.log(j2s(e.errorDetail)); +    } else { +      console.log(e); +    } +    throw e; +  } +} + +runExchangePurseTest.suites = ["wallet"]; diff --git a/packages/taler-harness/src/integrationtests/testrunner.ts b/packages/taler-harness/src/integrationtests/testrunner.ts index cbdca04b9..226fd6b09 100644 --- a/packages/taler-harness/src/integrationtests/testrunner.ts +++ b/packages/taler-harness/src/integrationtests/testrunner.ts @@ -14,7 +14,12 @@   GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>   */ -import { CancellationToken, Logger, minimatch, setGlobalLogLevelFromString } from "@gnu-taler/taler-util"; +import { +  CancellationToken, +  Logger, +  minimatch, +  setGlobalLogLevelFromString, +} from "@gnu-taler/taler-util";  import * as child_process from "child_process";  import * as fs from "fs";  import * as os from "os"; @@ -105,6 +110,7 @@ import { runPeerRepairTest } from "./test-peer-repair.js";  import { runPaymentShareTest } from "./test-payment-share.js";  import { runSimplePaymentTest } from "./test-simple-payment.js";  import { runTermOfServiceFormatTest } from "./test-tos-format.js"; +import { runExchangePurseTest } from "./test-exchange-purse.js";  /**   * Test runner. @@ -137,6 +143,7 @@ const allTests: TestMainFunction[] = [    runFeeRegressionTest,    runForcedSelectionTest,    runKycTest, +  runExchangePurseTest,    runExchangeDepositTest,    runLibeufinAnastasisFacadeTest,    runLibeufinApiBankaccountTest, | 
