api-donau.rst (23019B)
1 .. 2 This file is part of GNU TALER. 3 Copyright (C) 2014-2023 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 @author Christian Grothoff 17 @author Pius Loosli 18 @author Lukas Matyja 19 @author Johannes Casaburi 20 21 .. _donau-api: 22 23 ===================== 24 The Donau RESTful API 25 ===================== 26 27 The API specified here follows the :ref:`general conventions <http-common>` 28 for all details not specified in the individual requests. 29 The `glossary <https://docs.taler.net/taler-developer-manual.html#developer-glossary>`_ 30 defines all specific terms used in this section. 31 32 .. contents:: Table of Contents 33 :local: 34 35 .. _donau-overview: 36 37 ------------ 38 API Overview 39 ------------ 40 41 This is intended to provide a quick overview of the whole REST API. For a more detailed view of the protocol, see the protocol specification. 42 43 The chapters group the families of requests frequently encountered when using the Donau API: 44 45 * :ref:`Status information<donau_status>`: get the public signing keys of the Donau, the donation unit key, the Donaus config or some entropy 46 * :ref:`Issue receipts<donau_issue>`: For use by charities: Issue receipts with blinded unique donor ids from a donor. 47 * :ref:`Donation statement<donation_statement>`: Summarizes the donation receipts to the donation statement signature which is made over the total yearly donation amount, 48 the year and the hash of taxid+salt. Provides an API to get the donation statement signature. 49 * :ref:`Charity administration and status information<donau_charity>`: 50 51 * For use by administrators to add/modify a charity 52 * For use by charities to get their remaining donation volume 53 54 .. include:: tos.rst 55 56 .. _donau_status: 57 58 ---------------------------------------- 59 Donau public keys and status information 60 ---------------------------------------- 61 62 This API is used by donors and charities to obtain global information about 63 the Donau, such as online signing keys and available donation units. This is 64 typically the first call any Donau client makes, as it returns information 65 required to process all of the other interactions with the Donau. The 66 returned information is secured by signature(s) from the Donau, especially the 67 long-term offline signing key of the Donau, which clients should cache. 68 69 .. http:get:: /keys 70 71 Get a list of all donation units keys offered by the Donau, 72 as well as the Donau's current online signing key (used for donation statements). 73 74 **Request:** 75 76 **Response:** 77 78 :http:statuscode:`200 OK`: 79 The Donau responds with a `DonauKeysResponse` object. This request should 80 virtually always be successful. It only fails if the Donau is misconfigured. 81 82 **Details:** 83 84 .. ts:def:: DonauKeysResponse 85 86 interface DonauKeysResponse { 87 // libtool-style representation of the Donau protocol version, see 88 // https://www.gnu.org/software/libtool/manual/html_node/Versioning.html#Versioning 89 // The format is "current:revision:age". 90 version: string; 91 92 // Legal/financial domain this Donau operates for. Shown to the 93 // user by the wallet when selecting a Donau. Should match the 94 // name of the financial authority that the user would recognize. 95 legal_domain: string; 96 97 // The Donau's base URL. 98 base_url: string; 99 100 // The Donau's currency. 101 currency: string; 102 103 // Donation units offered by this Donau. Each entry enumerates a 104 // specific key together with its value and status. 105 donation_units: DonationUnit[]; 106 107 // The Donau's signing keys. 108 signkeys: SignKey[]; 109 110 } 111 112 .. ts:def:: DonationUnit 113 114 interface DonationUnit extends DonationUnitKeyCommon { 115 // How much a receipt signed with this key is worth. 116 value: Amount; 117 118 // Public key material of the donation unit. 119 donation_unit_pub: DonationUnitKey; 120 } 121 122 .. ts:def:: DonationUnitKeyCommon 123 124 interface DonationUnitKeyCommon { 125 126 // For which year is this donation unit key valid. 127 year: Integer; 128 129 // Set to 'true' if the Donau somehow "lost" the private key. The donation unit was not 130 // revoked, but still cannot be used to withdraw receipts at this time (theoretically, 131 // the private key could be recovered in the future; receipts signed with the private key 132 // remain valid). 133 lost?: boolean; 134 } 135 136 .. ts:def:: DonationUnitKey 137 138 type DonationUnitKey = 139 | RsaDonationUnitKey 140 | CSDonationUnitKey; 141 142 .. ts:def:: RsaDonationUnitKey 143 144 interface RsaDonationUnitKey { 145 cipher: "RSA"; 146 147 // RSA public key 148 rsa_public_key: RsaPublicKey; 149 150 // Hash of the RSA public key, as used in other API calls. 151 pub_key_hash: HashCode; 152 } 153 154 .. ts:def:: CSDonationUnitKey 155 156 interface CSDonationUnitKey { 157 cipher: "CS"; 158 159 // Public key of the donation unit. 160 cs_public_key: Cs25519Point; 161 162 // Hash of the CS public key, as used in other API calls. 163 pub_key_hash: HashCode; 164 } 165 166 A signing key in the ``signkeys`` list is a JSON object with the following fields: 167 168 .. ts:def:: SignKey 169 170 interface SignKey { 171 // The actual Donau's EdDSA signing public key. 172 key: EddsaPublicKey; 173 174 // Initial validity date for the signing key. 175 year: Integer; 176 177 } 178 179 180 .. note:: 181 182 Both the individual donation units *and* the donation units list is signed, 183 allowing customers to prove that they received an inconsistent list. 184 185 .. http:get:: /seed 186 187 Return an entropy seed. The Donau will return a high-entropy 188 value that will differ for every call. The response is NOT in 189 JSON, but simply high-entropy binary data in the HTTP body. 190 This API should be used by wallets to guard themselves against 191 running on low-entropy (bad PRNG) hardware. Naturally, the entropy 192 returned MUST be mixed with locally generated entropy. 193 194 .. http:get:: /config 195 196 Return the protocol version, financial domain and currency supported by this 197 Donau backend. 198 199 **Response:** 200 201 :http:statuscode:`200 OK`: 202 The body is a `DonauVersionResponse`. 203 204 .. ts:def:: DonauVersionResponse 205 206 interface DonauVersionResponse { 207 // libtool-style representation of the Donau protocol version, see 208 // https://www.gnu.org/software/libtool/manual/html_node/Versioning.html#Versioning 209 // The format is "current:revision:age". 210 version: string; 211 212 // Name of the protocol. 213 name: "donau"; 214 215 // Currency supported by this Donau. 216 currency: string; 217 218 // Financial domain by this Donau. 219 domain: string; 220 221 } 222 223 224 .. _donau_issue: 225 226 -------------- 227 Issue receipts 228 -------------- 229 230 Inspired by the Taler exchange :ref:`Withdrawal<exchange-withdrawal>`. 231 232 This API is used to obtain valid, attested donation receipts from the Donau. 233 Use the :ref:`charity GET route<donau_charity_get>` to see the remaining donation volume for the current year. 234 235 CSR Issue 236 ~~~~~~~~~~~ 237 238 .. http:post:: /csr-issue 239 240 Obtain donau-side input values in preparation for a 241 issue receipt step for certain donation unit cipher types, 242 specifically at this point for Clause-Schnorr blind 243 signatures. This API is used by the donor. 244 245 **Request:** The request body must be a `IssuePrepareRequest` object. 246 247 **Response:** 248 249 :http:statuscode:`200 OK`: 250 The request was successful, and the response is a `IssuePrepareResponse`. Note that repeating exactly the same request 251 will again yield the same response (assuming none of the donation unit is expired). 252 :http:statuscode:`404 Not found`: 253 The donation unit key is not known to the donau. 254 :http:statuscode:`410 Gone`: 255 The requested donation unit key is not yet or no longer valid. It either before the validity year, past the 256 year or was revoked. The response is a `DonationUnitExpiredMessage`. Clients must evaluate the error code provided to 257 understand which of the cases this is and handle it accordingly. 258 259 **Details:** 260 261 .. ts:def:: IssuePrepareRequest 262 263 interface IssuePrepareRequest { 264 265 // Nonce to be used by the donau to derive 266 // its private inputs from. Must not have ever 267 // been used before. 268 nonce: CSNonce; 269 270 // Hash of the public key of the donation unit 271 // the request relates to. 272 du_pub_hash: HashCode; 273 274 } 275 276 .. ts:def:: IssuePrepareResponse 277 278 type IssuePrepareResponse = 279 | DonauIssueValue; 280 281 .. ts:def:: DonauIssueValue 282 283 type DonauIssueValue = 284 | DonauRsaIssueValue 285 | DonauCsIssueValue; 286 287 .. ts:def:: DonauRsaIssueValue 288 289 interface DonauRsaIssueValue { 290 cipher: "RSA"; 291 } 292 293 .. ts:def:: DonauCsIssueValue 294 295 interface DonauCsIssueValue { 296 cipher: "CS"; 297 298 // CSR R0 value 299 r_pub_0: CSRPublic; 300 301 // CSR R1 value 302 r_pub_1: CSRPublic; 303 } 304 305 306 Batch Issue 307 ~~~~~~~~~~~ 308 This is the effectiv issue receipts request. Depending on the amount of the donation a 309 certain amount of blinded unique donation identifiers, or for short BUDIs, are required. 310 Every BUDI will be signed by the corresponding requested donation unit, which is associated with a value. 311 This API is used by the charity but the array of `BlindedDonationReceiptKeyPair` are coming from the donor. 312 313 To make the request idempotent, the hash of the hole request is recorded under the 314 corresponding charity_id by the Donau. 315 316 .. http:POST:: /batch-issue/$CHARITY_ID 317 318 Send in a `IssueReceiptsRequest` and ask the Donau to sign all it's contained BUDIs. 319 320 **Request:** `IssueReceiptsRequest` 321 322 **Response:** 323 324 :http:statuscode:`200 OK`: 325 The request was successful, and the response is a `BlindedDonationReceiptSignaturesResponse`. 326 :http:statuscode:`403 Forbidden`: 327 The charity signature is invalid. This response comes with a standard `ErrorDetail` response. 328 :http:statuscode:`404 Not found`: 329 At least one of the donation unit keys is not known to the Donau. Comes with a `DonationUnitUnknownError`. 330 This suggests a bug in the donor as it should have used current donation unit keys from :ref:`/keys<donau_status>`. 331 :http:statuscode:`409 Conflict`: 332 The donation volume of the charity is not sufficient to issue donation receipts for all sent in blinded udis. 333 The response is a `IssueError` object. 334 :http:statuscode:`410 Gone`: 335 The requested donation unit key is not yet or no longer valid. It either before the validity year, past the 336 year or was revoked. The response is a `DonationUnitExpiredMessage`. Clients must evaluate the error code 337 provided to understand which of the cases this is and handle it accordingly. 338 339 **Details:** 340 341 .. ts:def:: IssueReceiptsRequest 342 343 interface IssueReceiptsRequest { 344 345 // Signature by the charity approving that the 346 // Donau should sign the donation receipts below. 347 charity_sig: EddsaSignature; 348 349 // Year for which the donation receipts are expected. 350 // Also determines which keys are used to sign the 351 // blinded donation receipts. 352 year: Integer; 353 354 // Array of blinded donation receipts to sign. 355 // Must NOT be empty (if no donation receipts 356 // are desired, just leave the entire ``donau`` 357 // argument blank). 358 budikeypairs: BlindedDonationReceiptKeyPair[]; 359 } 360 361 .. ts:def:: BlindedDonationReceiptKeyPair 362 363 interface BlindedDonationReceiptKeyPair { 364 // Hash of the public key that should be used to sign 365 // the donation receipt. 366 h_donation_unit_pub: HashCode; 367 368 // Blinded value to give to the Donau to sign over. 369 blinded_udi: BlindedUniqueDonationIdentifier; 370 } 371 372 .. ts:def:: BlindedUniqueDonationIdentifier 373 374 type BlindedUniqueDonationIdentifier = RSABUDI | CSBUDI ; 375 376 .. ts:def:: RSABUDI 377 378 interface RSABUDI { 379 cipher: "RSA"; 380 rsa_blinded_identifier: string; // Crockford Base32 encoded 381 } 382 383 .. ts:def:: CSBUDI 384 385 // For donation unit signatures based on Blind Clause-Schnorr, the BUDI 386 // consists of the public nonce and two Curve25519 scalars which are two 387 // blinded challenges in the Blinded Clause-Schnorr signature scheme. 388 // See https://taler.net/papers/cs-thesis.pdf for details. 389 interface CSBUDI { 390 cipher: "CS"; 391 cs_nonce: string; // Crockford Base32 encoded 392 cs_blinded_c0: string; // Crockford Base32 encoded 393 cs_blinded_c1: string; // Crockford Base32 encoded 394 } 395 396 .. ts:def:: BUDIBlindingKeyP 397 398 // Secret for blinding/unblinding. 399 // An RSA blinding secret, which is basically 400 // a 256-bit nonce, converted to Crockford Base32. 401 type BUDIBlindingKeyP = string; 402 403 .. ts:def:: BlindedDonationReceiptSignaturesResponse 404 405 interface BlindedDonationReceiptSignaturesResponse { 406 // Total amount over which all the blind signatures are signing. 407 issued_amount: Amount; 408 409 // Array of the blind signatures. 410 blind_signatures: BlindedDonationReceiptSignature[]; 411 } 412 413 .. ts:def:: BlindedDonationReceiptSignature 414 415 type BlindedDonationReceiptSignature = 416 | RSABlindedDonationReceiptSignature 417 | CSBlindedDonationReceiptSignature; 418 419 .. ts:def:: RSABlindedDonationReceiptSignature 420 421 interface RSABlindedDonationReceiptSignature { 422 cipher: "RSA"; 423 424 // (blinded) RSA signature 425 blinded_rsa_signature: BlindedRsaSignature; 426 } 427 428 .. ts:def:: CSBlindedDonationReceiptSignature 429 430 interface CSBlindedDonationReceiptSignature { 431 cipher: "CS"; 432 433 // Signer chosen bit value, 0 or 1, used 434 // in Clause Blind Schnorr to make the 435 // ROS problem harder. 436 b: Integer; 437 438 // Blinded scalar calculated from c_b. 439 s: Cs25519Scalar; 440 } 441 442 .. ts:def:: IssueError 443 444 interface IssueError{ 445 max_per_year: Amount; 446 current_year: Amount; 447 } 448 449 .. ts:def:: DonationUnitUnknownError 450 451 interface DonationUnitUnknownError{ 452 unknown_hash_pub_donation_unit: HashCode[]; 453 donau_pub: EddsaPublicKey; 454 donau_sig: EddsaSignature; 455 } 456 457 .. ts:def:: DonationUnitExpiredMessage 458 459 interface DonationUnitExpiredMessage{ 460 h_donation_unit_pub: HashCode; 461 donau_pub: EddsaPublicKey; 462 donau_sig: EddsaSignature; 463 } 464 465 .. _donation_statement: 466 467 ------------------ 468 Donation statement 469 ------------------ 470 471 Inspired by the Taler exchange :ref:`Deposit<deposit-par>`. 472 473 Donation statement operations are requested by a donor. 474 475 .. http:POST:: /batch-submit 476 477 Send in donation receipts for the current or one of the past fiscal years. 478 The donor will reveive the signed total back, which is called the 479 donation statement. 480 481 **Request:** `SubmitDonationReceiptsRequest` 482 483 **Response:** 484 485 :http:statuscode:`201 Created`: 486 The request was successful, and a donation statement is now available. The response will be empty. 487 :http:statuscode:`403 Forbidden`: 488 One of the signatures is invalid. This response comes with a standard `ErrorDetail` response. 489 :http:statuscode:`404 Not found`: 490 At least one of the donation unit keys is not known to the Donau. Comes with a `DonationUnitUnknownError`. 491 492 **Details:** 493 494 .. ts:def:: SubmitDonationReceiptsRequest 495 496 interface SubmitDonationReceiptsRequest{ 497 // hashed taxpayer ID plus salt 498 h_donor_tax_id: HashCode; 499 // All donation receipts must be for this year. 500 donation_year: Integer; 501 // Receipts should be sorted by amount. 502 donation_receipts: DonationReceipt[]; 503 } 504 505 .. ts:def:: DonationReceipt 506 507 interface DonationReceipt { 508 h_donation_unit_pub: HashCode; 509 nonce: string; 510 donation_unit_sig: DonationReceiptSignature; 511 } 512 513 .. ts:def:: DonationReceiptSignature 514 515 type DonationReceiptSignature = RSADonationReceiptSignature | CSDonationReceiptSignature ; 516 517 .. ts:def:: RSADonationReceiptSignature 518 519 interface RSADonationReceiptSignature { 520 cipher: "RSA"; 521 522 // RSA signature 523 rsa_signature: RsaSignature; 524 } 525 526 .. ts:def:: CSDonationReceiptSignature 527 528 interface CSDonationReceiptSignature { 529 cipher: "CS"; 530 531 // R value component of the signature. 532 cs_signature_r: Cs25519Point; 533 534 // s value component of the signature. 535 cs_signature_s: Cs25519Scalar; 536 } 537 538 .. http:GET:: /donation-statement/$YEAR/$HASH_DONOR_ID 539 540 Get the donation statement for a specific year and donor. 541 542 **Request:** 543 544 **Response:** 545 546 :http:statuscode:`200 OK`: 547 The request was successful, and the response is a `DonationStatementResponse`. 548 :http:statuscode:`403 Forbidden`: 549 One of the signatures is invalid. This response comes with a standard `ErrorDetail` response. 550 :http:statuscode:`404 Not found`: 551 Either the donor or the year or the corresponding donation statement was not found. 552 This response comes with a standard `ErrorDetail` response. 553 554 **Details:** 555 556 .. ts:def:: DonationStatementResponse 557 558 interface DonationStatementResponse { 559 total: Amount; 560 // signature over h_donor_tax_id, total, donation_year 561 donation_statement_sig: EddsaSignature; 562 // the corresponding public key to the signature 563 donau_pub: EddsaPublicKey; 564 } 565 566 .. _donau_charity: 567 568 --------------------------------------------- 569 Charity administration and status information 570 --------------------------------------------- 571 572 The administration requests require an authorized bearer token to be set in the HTTP "Authorization" Header. This token can be set by a proxy validating authentication/authorization (using e.g. LDAP). 573 The GET status requests require an authorized bearer token as well. 574 575 .. http:GET:: /charities 576 577 GET all charities. Only allowed if the request comes with the administration bearer token. 578 579 return all charities 580 581 **Request:** 582 583 **Reponse:** 584 585 :http:statuscode:`200 OK`: 586 The request was successful, and the response is a `Charities`. 587 588 **Details:** 589 590 .. ts:def:: Charities 591 592 interface Charities{ 593 charities: CharitySummary[]; 594 } 595 596 .. ts:def:: CharitySummary 597 598 interface CharitySummary { 599 600 // Unique ID of the charity within the Donau. 601 charity_id: Integer; 602 603 // Public key of the charity, used by the charity to 604 // authorize issuing donation receipts. 605 charity_pub: EddsaPublicKey; 606 607 // Human-readable name of the charity. 608 charity_name: string; 609 610 // Maximum amount of donation receipts this charity is 611 // allowed to issue per year. 612 max_per_year: Amount; 613 614 // Year for which ``receipts_to_date`` is given. 615 current_year: Integer; 616 617 // Total amount of donation receipts the donau has 618 // issued for this charity so far this year. 619 receipts_to_date: Amount; 620 } 621 622 .. _donau_charity_get: 623 624 .. http:get:: /charity/$CHARITY_ID 625 626 Request information about a specific charity. 627 Only allowed if the request comes with a signature by 628 the respective charity. 629 630 **Request:** 631 632 *Charity-Signature*: 633 634 The client must provide Base-32 encoded EdDSA signature with 635 ``$CHARITY_PRIV``, affirming the desire to obtain the charity status. 636 Note that this is merely a simple authentication mechanism, 637 the details of the request are not protected by the signature. 638 The ``$CHARITY_PRIV`` is usually the merchant instance 639 private key. 640 641 **Response:** 642 643 :http:statuscode:`200 OK`: 644 The Donau responds with a `Charity` object 645 :http:statuscode:`404 Not found`: 646 The charity id does not belong to a charity known to the Donau. 647 648 .. ts:def:: Charity 649 650 interface Charity { 651 charity_pub: EddsaPublicKey; 652 name: string; 653 url: string; 654 max_per_year: Amount; 655 receipts_to_date: Amount; 656 current_year: Integer; 657 } 658 659 .. http:POST:: /charities 660 661 Register a new charity with the Donau. Only allowed if the request comes with the 662 administrator bearer token. The request body defines the charity's signing key, 663 contact information, and the initial accounting values for the current business 664 year. On success the Donau assigns a numeric identifier to the charity record. 665 666 **Request:** `CharityRequest` 667 668 **Response:** 669 670 **Details:** 671 672 :http:statuscode:`201 Created`: 673 The request was successful, and the response is a `CharityResponse`. 674 675 :http:statuscode:`403 Forbidden`: 676 The request did not contain an accepted administrator bearer token in its header. 677 678 :http:statuscode:`404 Not found`: 679 The referenced resource needed to create the charity was not found. This response 680 comes with a standard `ErrorDetail` response. 681 682 :http:statuscode:`409 Conflict`: 683 A charity with the same public key exists in the backend, but it 684 has different details. This response 685 comes with a standard `ErrorDetail` response. 686 687 .. ts:def:: CharityRequest 688 689 interface CharityRequest { 690 691 // Long-term EdDSA public key that identifies the charity. 692 charity_pub: EddsaPublicKey; 693 694 // Canonical URL that should be presented to donors. 695 charity_url: string; 696 697 // Human-readable display name of the charity. 698 charity_name: string; 699 700 // Allowed donation volume for the charity per calendar year. 701 max_per_year: Amount; 702 } 703 704 .. ts:def:: CharityResponse 705 706 interface CharityResponse { 707 708 // Unique ID assigned to the charity in the backend. 709 charity_id: Integer; 710 } 711 712 713 .. http:PATCH:: /charities/{charity_id} 714 715 Modify a charity. 716 Only allowed if the request comes with the administrator bearer token. 717 718 **Request:** ``CharityRequest`` 719 720 **Response:** 721 722 :http:statuscode:`200 OK`: 723 The update succeeded. The response body is empty. 724 725 :http:statuscode:`400 Bad Request`: 726 The request was malformed. For example, ``max_per_year`` must not be 727 smaller than the current ``receipts_to_date`` of the charity. 728 729 :http:statuscode:`401 Unauthorized`: 730 Missing or invalid bearer token. 731 732 :http:statuscode:`403 Forbidden`: 733 The request did not contain an accepted administrator bearer token in its header. 734 735 :http:statuscode:`404 Not Found`: 736 The charity ID is unknown to the Donau. 737 738 **Details:** 739 740 The request body has the same shape as :ts:type:`CharityRequest` used by 741 :http:POST:`/charities`. All fields are required and will replace the stored 742 values of the charity. 743 744 745 .. http:DELETE:: /charities/{charity_id} 746 747 Delete (or deactivate) a charity. Only allowed if the request comes with the administrator bearer token. 748 749 **Request:** 750 751 **Response:** 752 753 :http:statuscode:`204 No content`: 754 The request was successful. 755 756 :http:statuscode:`403 Forbidden`: 757 The request did not contain an accepted administrator bearer token in it's header.