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.