taler-docs

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

taler-wallet.rst (20703B)


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