taler-docs

Documentation for GNU Taler components, APIs and protocols
Log | Files | Refs | README | LICENSE

taler-wallet-developer.rst (20803B)


      1 ..
      2   This file is part of GNU TALER.
      3   Copyright (C) 2014-2024 Taler Systems SA
      4 
      5   TALER is free software; you can redistribute it and/or modify it under the
      6   terms of the GNU Affero General Public License as published by the Free Software
      7   Foundation; either version 2.1, or (at your option) any later version.
      8 
      9   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
     10   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
     11   A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more details.
     12 
     13   You should have received a copy of the GNU Affero General Public License along with
     14   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
     15 
     16 
     17 Wallet Developer Manual
     18 #######################
     19 
     20 .. note::
     21 
     22   This manual contains information for developers working on the wallet
     23   component of GNU Taler.  It is not intended for a general audience.
     24 
     25 
     26 The GNU Taler wallet allows customers to withdraw and spend digital cash.
     27 
     28 
     29 WebExtension Wallet
     30 ===================
     31 
     32 Building from source
     33 --------------------
     34 
     35 .. code-block:: console
     36 
     37   $ git clone https://git.taler.net/wallet-core.git
     38   $ cd wallet-core
     39   $ ./configure
     40   $ make webex-stable
     41   # Packaged extension now available as:
     42   # dist/taler-wallet-$VERSION.zip
     43 
     44 
     45 Android Wallet
     46 ==============
     47 
     48 Please see :ref:`Build-apps-from-source` in the :doc:`taler-developer-manual`.
     49 
     50 
     51 iOS Wallet
     52 ==========
     53 
     54 Please see :ref:`Build-iOS-from-source` in the :doc:`taler-developer-manual`.
     55 
     56 .. _command-line-wallet:
     57 
     58 Command-line Wallet
     59 ===================
     60 
     61 This section describes how to use the GNU Taler wallet command line
     62 interface (CLI).
     63 
     64 The the wallet CLI is targeted at developers and operators, but not meant to be
     65 used by customers.  It exposes all functionality that the more user-friendly
     66 interfaces (Android app, browser extension) offer.  However, it provides more
     67 diagnostics and advanced features as well.
     68 
     69 Building from source
     70 --------------------
     71 
     72 The easiest way to install the wallet is via NPM.  Note that a recent version of
     73 Node.JS (``>=12.20.1``) is required.
     74 
     75 We recommend to install the wallet package on a per-user basis,
     76 thus setting ``$INSTALL_PREFIX`` to a directory in ``$HOME``.
     77 
     78 .. code-block:: console
     79 
     80   $ git clone https://git.taler.net/wallet-core.git
     81   $ cd wallet-core
     82   $ ./bootstrap
     83   $ ./configure --prefix=$INSTALL_PREFIX
     84   $ make && make install
     85 
     86 The wallet command-line interface should then be available as ``taler-wallet-cli`` under ``$INSTALL_PREFIX/bin``.
     87 
     88 Installation via NPM
     89 --------------------
     90 
     91 The wallet can also obtained via NPM, the Node Package Manager.
     92 
     93 To install the wallet as a global package, run:
     94 
     95 .. code-block:: console
     96 
     97   $ npm install -g taler-wallet
     98   # check if installation was successful
     99   $ taler-wallet-cli --version
    100 
    101 To install the wallet only for your user, run:
    102 
    103 .. code-block:: console
    104 
    105   $ npm install -g --prefix=$HOME/local taler-wallet
    106   # check if installation was successful
    107   $ taler-wallet-cli --version
    108   # If this fails, make sure that $HOME/local/bin is in your $PATH
    109 
    110 To use the wallet as a library in your own project, run:
    111 
    112 .. code-block:: console
    113 
    114   $ npm install taler-wallet
    115 
    116 
    117 Getting Help
    118 ------------
    119 
    120 The wallet CLI comes with built-in help.  Invoke the wallet CLI (or any subcommand) with the ``--help`` flag to get help:
    121 
    122 .. code-block:: console
    123 
    124   $ taler-wallet-cli --help
    125   Usage: taler-wallet-cli COMMAND
    126 
    127   Command line interface for the GNU Taler wallet.
    128 
    129   Options:
    130     -h, --help             Show this message and exit.
    131     --wallet-db=VALUE      location of the wallet database file
    132     --timetravel=VALUE     modify system time by given offset in microseconds
    133     --inhibit=VALUE        Inhibit running certain operations, useful for debugging and testing.
    134     --no-throttle          Don't do any request throttling.
    135     -v, --version
    136     -V, --verbose          Enable verbose output.
    137 
    138   Commands:
    139     advanced               Subcommands for advanced operations (only use if you know what you're doing!).
    140     api                    Call the wallet-core API directly.
    141     backup                 Subcommands for backups
    142     balance                Show wallet balance.
    143     deposit                Subcommands for depositing money to payto:// accounts
    144     exchanges              Manage exchanges.
    145     handle-uri             Handle a taler:// URI.
    146     pending                Show pending operations.
    147     run-pending            Run pending operations.
    148     run-until-done         Run until no more work is left.
    149     testing                Subcommands for testing GNU Taler deployments.
    150     transactions           Show transactions.
    151 
    152 Completing operations
    153 ---------------------
    154 
    155 Note that the CLI does not run as a background daemon.  When starting
    156 operations that don't immediately finish, the wallet needs to be run explicitly
    157 to finish any pending tasks:
    158 
    159 
    160 .. code-block:: console
    161 
    162   # Do one attempt to finish all pending operations
    163   $ taler-wallet-cli run-pending
    164 
    165   # Run until all work is done
    166   $ taler-wallet-cli run-until-done
    167 
    168 Resetting the wallet
    169 --------------------
    170 
    171 The wallet can be reset by deleting its database file.  By default, the database file
    172 is ``$HOME/.talerwalletdb.sqlite3``.
    173 
    174 
    175 Handling taler:// URIs
    176 ----------------------
    177 
    178 Many interactions with the Taler wallet happen by scanning QR codes or special
    179 headers on Websites.  To emulate this with the command line interface, run the following
    180 command:
    181 
    182 .. code-block:: console
    183 
    184   $ taler-wallet-cli handle-uri $URI
    185 
    186 
    187 Manual withdrawing
    188 ------------------
    189 
    190 .. code-block:: console
    191 
    192   $ taler-wallet-cli advanced withdraw-manually \
    193       --exchange https://exchange.eurint.taler.net/ \
    194       --amount EUR:5
    195 
    196 
    197 P2P push payments
    198 -----------------
    199 
    200 The following code generates a P2P push transaction over 1 CHF
    201 with an expiration time of 30 days (assuming the wallet has a
    202 sufficient balance):
    203 
    204 .. code-block:: console
    205 
    206   $ taler-wallet-cli p2p initiate-push-debit \
    207       --purse-expiration="30 d" \
    208       --summary="The summary" \
    209       CHF:1
    210 
    211 The final URL can then be found in the transaction list:
    212 
    213 .. code-block:: console
    214 
    215   $ taler-wallet-cli transactions
    216 
    217 Background wallet
    218 -----------------
    219 
    220 A wallet can be launched in the background:
    221 
    222 .. code-block:: console
    223 
    224   $ taler-wallet-cli advanced serve &
    225 
    226 You can then run various Taler operations faster against
    227 this one persistent instance:
    228 
    229 .. code-block:: console
    230 
    231   $ taler-wallet-cli --wallet-connection=wallet-core.sock ...
    232 
    233 Here ``...`` needs to be changed to the commando to run.
    234 Make sure to run
    235 
    236 .. code-block:: console
    237 
    238   $ taler-wallet-cli --wallet-connection=wallet-core.sock \
    239       run-until-done
    240 
    241 to wait for pending transactions to complete.
    242 
    243 
    244 Testing an exchange deployment
    245 ------------------------------
    246 
    247 The following series of commands can be used to check that an exchange deployment
    248 is functional:
    249 
    250 .. code-block:: console
    251 
    252   # This will now output a payto URI that money needs to be sent to in order to allow withdrawal
    253   # of taler coins
    254   $ taler-wallet-cli advanced withdraw-manually --exchange $EXCHANGE_URL --amount EUR:10.50
    255 
    256   # Show the status of the manual withdrawal operation
    257   $ taler-wallet-cli transactions
    258 
    259   # Once the transfer has been made, try completing the withdrawal
    260   $ taler-wallet-cli run-pending
    261 
    262   # Check status of transactions and show balance
    263   $ taler-wallet-cli transactions
    264   $ taler-wallet-cli balance
    265 
    266   # Now, directly deposit coins with the exchange into a target account
    267   # (Usually, a payment is made via a merchant.  The wallet provides
    268   # this functionality for testing.)
    269   $ taler-wallet-cli deposit create EUR:5 payto://iban/$IBAN
    270 
    271   # Check if transaction was successful.
    272   # (If not, fix issue with exchange and run "run-pending" command again)
    273   $ taler-wallet-cli transactions
    274 
    275   # The wallet can also track if the exchange wired the money to the merchant account.
    276   # The "deposit group id" can be found in the output of the transactions list.
    277   $ taler-wallet-cli deposit track $DEPOSIT_GROUP_ID
    278 
    279 
    280 APIs and Data Formats
    281 =====================
    282 
    283 Envelope Format
    284 ---------------
    285 
    286 All API responses and notifications are returned in the
    287 following envelope:
    288 
    289 .. ts:def:: WalletResponseEnvelope
    290 
    291    type WalletResponseEnvelope =
    292     | WalletSuccess
    293     | WalletError
    294     | WalletNotification
    295 
    296 .. ts:def:: WalletSuccess
    297 
    298    export interface WalletSuccess {
    299      type: "response";
    300      operation: string;
    301      // ID to correlate success response to request
    302      id: string;
    303      // Result type depends on operation
    304      result: unknown;
    305    }
    306 
    307 .. ts:def:: WalletError
    308 
    309    export interface WalletError {
    310      type: "error";
    311      operation: string;
    312      // ID to correlate error response to request
    313      id: string;
    314      error: WalletErrorInfo;
    315    }
    316 
    317 .. ts:def:: WalletNotification
    318 
    319    export interface WalletSuccess {
    320      type: "notification";
    321 
    322      // actual type is WalletNotification,
    323      // to be documented here
    324      payload: any;
    325    }
    326 
    327 .. ts:def:: WalletErrorInfo
    328 
    329    export interface WalletErrorInfo {
    330      // Numeric error code defined defined in the
    331      // GANA gnu-taler-error-codes registry.
    332      talerErrorCode: number;
    333 
    334      // English description of the error code.
    335      talerErrorHint: string;
    336 
    337      // English diagnostic message that can give details
    338      // for the instance of the error.
    339      message: string;
    340 
    341      // Error details, type depends
    342      // on talerErrorCode
    343      details: unknown;
    344    }
    345 
    346 Withdrawal
    347 ----------
    348 
    349 A typical API sequence for *bank-integrated* withdrawals can for example look like this:
    350 
    351 #. ``"getWithdrawalDetailsForUri"`` returns an amount and default exchange
    352 #. ``"getWithdrawalDetailsForAmount"`` returns fee information and that ToS are not accepted
    353 
    354    #. ``"getExchangeTos"`` are shown to the user and return currentEtag
    355    #. ``"setExchangeTosAccepted"`` called with currentEtag after user accepted
    356 
    357 #. ``"acceptWithdrawal"`` after the user confirmed withdrawal with associated fees
    358 
    359 A typical API sequence for *manual* withdrawals can for example look like this:
    360 
    361 #. ``"listExchanges"`` shows a list of exchanges to the user who picks one and an amount
    362 #. ``"getWithdrawalDetailsForAmount"`` returns fee information and that ToS are not accepted
    363 
    364    #. ``"getExchangeTos"`` are shown to the user and return currentEtag
    365    #. ``"setExchangeTosAccepted"`` called with currentEtag after user accepted
    366 
    367 #. ``"acceptManualWithdrawal"`` after the user confirmed withdrawal with associated fees
    368 
    369 Integration Tests
    370 =================
    371 
    372 Integration Test Example
    373 ------------------------
    374 
    375 Integration tests can be done with the low-level wallet commands.  To select which coins and denominations
    376 to use, the wallet can dump the coins in an easy-to-process format (`CoinDumpJson <https://git.taler.net/taler-typescript-core.git/tree/packages/taler-util/src/types-taler-wallet.ts#n613>`__).
    377 
    378 The database file for the wallet can be selected with the ``--wallet-db``
    379 option.  This option must be passed to the ``taler-wallet-cli`` command and not
    380 the subcommands.  If the database file doesn't exist, it will be created.
    381 
    382 The following example does a simple withdrawal recoup:
    383 
    384 .. code-block:: console
    385 
    386   # Withdraw digital cash
    387   $ taler-wallet-cli --wallet-db=mydb.sqlite3 testing withdraw \
    388       -b https://bank.int.taler.net/ \
    389       -e https://exchange.int.taler.net/ \
    390       -a INTKUDOS:10
    391 
    392   $ coins=$(taler-wallet-cli --wallet-db=mydb.sqlite3 advanced dump-coins)
    393 
    394   # Find coin we want to revoke
    395   $ rc=$(echo "$coins" | \
    396          jq -r '[.coins[] | select((.denom_value == "INTKUDOS:5"))][0] | .coin_pub')
    397 
    398   # Find the denom
    399   $ rd=$(echo "$coins" | \
    400          jq -r '[.coins[] | select((.denom_value == "INTKUDOS:5"))][0] | .denom_pub_hash')
    401 
    402   # Find all other coins, which will be suspended
    403   $ susp=$(echo "$coins" | \
    404            jq --arg rc "$rc" '[.coins[] | select(.coin_pub != $rc) | .coin_pub]')
    405 
    406   # The exchange revokes the denom
    407   $ taler-exchange-keyup -r $rd
    408   $ taler-deployment-restart
    409 
    410   # Now we suspend the other coins, so later we will pay with the recouped coin
    411   $ taler-wallet-cli --wallet-db=mydb.sqlite3 advanced suspend-coins "$susp"
    412 
    413   # Update exchange /keys so recoup gets scheduled
    414   $ taler-wallet-cli --wallet-db=mydb.sqlite3 exchanges update -f https://exchange.int.taler.net/
    415 
    416   # Block until scheduled operations are done
    417   $ taler-wallet-cli --wallet-db=mydb.sqlite3 run-until-done
    418 
    419   # Now we buy something, only the coins resulting from recouped will be
    420   # used, as other ones are suspended
    421   $ taler-wallet-cli --wallet-db=mydb.sqlite3 testing test-pay \
    422       -m https://backend.int.taler.net/ \
    423       -k sandbox \
    424       -a "INTKUDOS:1" \
    425       -s "foo"
    426   $ taler-wallet-cli --wallet-db=mydb.sqlite3 run-until-done
    427 
    428 
    429 To test refreshing, force a refresh:
    430 
    431 .. code-block:: console
    432 
    433   $ taler-wallet-cli --wallet-db=mydb.sqlite3 advanced force-refresh "$coin_pub"
    434 
    435 
    436 To test zombie coins, use the timetravel option. It **must** be passed to the
    437 top-level command and not the subcommand:
    438 
    439 .. code-block:: console
    440 
    441   # Update exchange /keys with time travel, value in microseconds
    442   $ taler-wallet-cli --timetravel=1000000 --wallet-db=mydb.sqlite3 \
    443       exchanges update -f https://exchange.int.taler.net/
    444 
    445 
    446 Integration Test and Fault Injection Framework
    447 ----------------------------------------------
    448 
    449 This section describes the current approach to integration testing in the wallet.
    450 
    451 It's all based on a TypeScript harness process, which itself implements
    452 the fault injection proxy (async and in-process)!
    453 
    454 The new approach consists of the following parts:
    455 
    456 1. A strongly typed, convenient helper library to easily set up and run
    457 arbitrary Taler deployments and run test cases.  These components plug
    458 together as easily as lego bricks, even with multiple
    459 exchanges/merchants/banks/etc.  Logs and clean shutdown (even on SIGINT
    460 or errors) are handled properly.  (Support for auditors is still pending
    461 but needed to fully test the wallet.)
    462 
    463 This is how a simple withdrawal and payment test case looks like:
    464 `<https://git.taler.net/taler-typescript-core.git/tree/packages/taler-harness/src/integrationtests/test-payment.ts>`__
    465 
    466 (What's particularly nice is that all our docs contain TypeScript
    467 definitions for all API request bodies.  So just copying them into the
    468 test harness gives us auto-completion and compile-time checks to avoid
    469 typos.  The wallet's JSON validation machinery is also re-used.)
    470 
    471 2. A fault injection proxy that can be plugged between the services
    472 and/or the wallet.  It runs alongside the test harness, and can thus can
    473 use arbitrary custom logic.  There's no dependency for it other than
    474 built-in Node.JS libraries.  Simple fault injections are just as easy to
    475 set up as with the twister.
    476 
    477 The following test case (a) logs all requests and responses to the test
    478 harness stdout and (b) at a certain point, starts dropping the next 10
    479 requests to the exchange (testing the wallet's retry logic):
    480 
    481 `<https://git.taler.net/taler-typescript-core.git/tree/packages/taler-harness/src/integrationtests/test-payment-fault.ts#n165>`__
    482 
    483 3. All util functionality from JS wallet-core, such as the Taler crypto,
    484 amount/date/etc. handling and JSON parsing/validation (the wallet is now
    485 more modular and easier to use as a library) can be used in the
    486 integration tests, even if a different wallet (Kotlin, whatever) is
    487 tested via the CLI.
    488 
    489 4. A bunch of test cases that use (1)-(3).  These are *significantly*
    490 more readable and hackable than other test approaches we had, while
    491 allowing for more complex scenarios.  There are still way too few tests
    492 though!
    493 
    494 5. A test runner (written in bash) that runs test cases based on a glob
    495 pattern and reports the results.
    496 
    497 Injecting a fault is as easy as:
    498 
    499 .. code:: ts
    500 
    501   // Set up test case
    502   [...]
    503 
    504   exchangeProxy.addFault({
    505     beforeResponse(ctx: FaultInjectionResponseContext) {
    506        if (cond1) { // Drop some responses
    507          ctx.dropResponse = true;
    508          return;
    509        } else if (cond2) { // modify some others
    510          ctx.responseBody = Buffer.from(`{"oops": true}`, "utf-8");
    511          return;
    512        }
    513        // Other things that can be modified:
    514        // - drop/modify the request, not just the response
    515        // - modify headers
    516        // - modify status codes
    517     }
    518   });
    519 
    520   await doSomethingWithTheWallet();
    521 
    522   exchangeProxy.clearFault();
    523 
    524   await doMoreWithTheWallet();
    525 
    526 
    527 To make the configuration easy, an ``ExchangeService`` (or ``MerchantService``,
    528 ``BankService`` etc.) can be wrapped in a ``FaultInjectedExchangeService``,
    529 which implements the ``ExchangeServiceInterface``:
    530 
    531 .. code:: ts
    532 
    533   // create exchange and two merchants
    534   const exchange = await setupExchange(...);
    535   const merchant1 = ...;
    536   const merchant2 = ...;
    537 
    538   // Add exchange to merchant-accepted exchanges.
    539   // This will adjust the config.
    540   merchant1.addExchange(exchange);
    541 
    542   // Wrap exchange in fault injection proxy
    543   const faultInjectedExchange: ExchangeServiceInterface
    544     = new FaultInjectedExchangeService(t, exchange1, 8085);
    545 
    546   // Merchant 2 talks to the exchange over fault injection,
    547   // and thus must use the "twisted" base URL.
    548   merchant2.addExchange(faultInjectedExchange);
    549 
    550 
    551 The package for the integration tests is here:
    552 
    553 `<https://git.taler.net/wallet-core.git/tree/packages/taler-harness>`__
    554 
    555 The integration tests are run via the ``taler-harness`` tool.
    556 
    557 .. code:: sh
    558 
    559   ./bootstrap && ./configure --prefix=... && make install
    560   taler-harness run-integrationtests
    561 
    562 
    563 Dev Experiments
    564 ===============
    565 
    566 Dev experiments allow simulating certain scenarios that are difficult to
    567 reproduce otherwise.  This allows more comprehensive (manual) testing of the
    568 UIs.
    569 
    570 You can enable dev experiments by putting the wallet into dev mode and then
    571 scanning the QR code for a ``taler://dev-experiment`` URI that specifies the
    572 desired dev experiment.
    573 
    574 Faking Protocol Versions
    575 ------------------------
    576 
    577 The ``start-fakeprotover`` dev experiment can be used to fake the protocol
    578 version reported by Taler components.  It mocks the ``version`` field in the
    579 response to ``/config`` or ``/keys``.
    580 
    581 Usage:
    582 
    583 .. code:: none
    584 
    585    taler://dev-experiment/start-fakeprotover?base_url=...&fake_ver=...
    586 
    587 Example:
    588 
    589 .. code:: none
    590 
    591    # Fake version 10:0:0 for https://exchange.demo.taler.net/
    592    taler://dev-experiment/start-fakeprotover?base_url=https%3A%2F%2Fexchange.demo.taler.net%2F&fake_ver=10%3A0%3A0
    593 
    594 
    595 Faking Transactions
    596 -------------------
    597 
    598 
    599 **Withdrawal Transaction:**
    600 
    601 .. code:: none
    602 
    603    taler://dev-experiment/add-fake-tx?txType=withdrawal&amountEffective=KUDOS:5
    604 
    605 Options:
    606 
    607 * ``amountEffective``: Mandatory. Effective amount of the withdrawal.
    608 * ``tRel``: Optional (defaults to ``0s``). Relative time that indicates
    609   when in the past the transaction was started (and finished).
    610 * ``exchangeBaseUrl``. Optional (defaults to ``https://exchange.demo.taler.net``).
    611   Exchange base URL used for the withdrwal.
    612 
    613 
    614 **Payment Transaction:**
    615 
    616 .. code:: none
    617 
    618    taler://dev-experiment/add-fake-tx?txType=payment&amountEffective=KUDOS:5
    619 
    620 Options:
    621 
    622 * ``amountEffective``: Mandatory. Effective amount of the withdrawal.
    623 * ``tRel``: Optional (defaults to ``0s``). Relative time that indicates
    624   when in the past the transaction was started (and finished).
    625 * ``exchangeBaseUrl``. Optional (defaults to ``https://exchange.demo.taler.net``).
    626   Exchange base URL used for the payment.
    627 * ``merchantBaseUrl``. Optional (defaults to ``https://backend.demo.taler.net/``).
    628 * ``merchantName``. Optional (defaults to ``Test Merchant``). Display name
    629   of the merchant in the contract terms of the transaction.
    630 * ``summary``. Optional (defaults to ``Test``). Summary in the contract terms of the
    631   transaction.
    632 
    633 **Peer Push Credit Transaction:**
    634 
    635 .. code:: none
    636 
    637    taler://dev-experiment/add-fake-tx?txType=peer-push-credit&amountEffective=KUDOS:5
    638 
    639 Options:
    640 
    641 * ``amountEffective``: Mandatory. Effective amount of the withdrawal.
    642 * ``tRel``: Optional (defaults to ``0s``). Relative time that indicates
    643   when in the past the transaction was started (and finished).
    644 * ``exchangeBaseUrl``. Optional (defaults to ``https://exchange.demo.taler.net``).
    645   Exchange base URL used for the payment.
    646 * ``summary``. Optional (defaults to ``Test``). Summary in the contract terms of the
    647   transaction.
    648 
    649 **Peer Push Debit Transaction:**
    650 
    651 .. code:: none
    652 
    653    taler://dev-experiment/add-fake-tx?txType=peer-push-debit&amountEffective=KUDOS:5
    654 
    655 Options:
    656 
    657 * ``amountEffective``: Mandatory. Effective amount of the withdrawal.
    658 * ``tRel``: Optional (defaults to ``0s``). Relative time that indicates
    659   when in the past the transaction was started (and finished).
    660 * ``exchangeBaseUrl``. Optional (defaults to ``https://exchange.demo.taler.net``).
    661   Exchange base URL used for the payment.
    662 * ``summary``. Optional (defaults to ``Test``). Summary in the contract terms of the
    663   transaction.