LCOV - code coverage report
Current view: top level - wire - plugin_wire_sepa.c (source / functions) Hit Total Coverage
Test: rcoverage.info Lines: 134 208 64.4 %
Date: 2017-11-25 11:31:41 Functions: 10 19 52.6 %

          Line data    Source code
       1             : /*
       2             :   This file is part of TALER
       3             :   Copyright (C) 2016, 2017 GNUnet e.V. & Inria
       4             : 
       5             :   TALER is free software; you can redistribute it and/or modify it under the
       6             :   terms of the GNU General Public License as published by the Free Software
       7             :   Foundation; either version 3, 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 General Public License for more details.
      12             : 
      13             :   You should have received a copy of the GNU General Public License along with
      14             :   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
      15             : */
      16             : 
      17             : /**
      18             :  * @file plugin_wire_sepa.c
      19             :  * @brief wire plugin for transfers using SEPA/EBICS
      20             :  * @author Florian Dold
      21             :  * @author Christian Grothoff
      22             :  * @author Sree Harsha Totakura
      23             :  */
      24             : #include "platform.h"
      25             : #include "taler_wire_plugin.h"
      26             : #include "taler_signatures.h"
      27             : #include <gnunet/gnunet_json_lib.h>
      28             : 
      29             : 
      30             : /**
      31             :  * Type of the "cls" argument given to each of the functions in
      32             :  * our API.
      33             :  */
      34             : struct SepaClosure
      35             : {
      36             : 
      37             :   /**
      38             :    * Which currency do we support?
      39             :    */
      40             :   char *currency;
      41             : 
      42             : };
      43             : 
      44             : 
      45             : /**
      46             :  * Round amount DOWN to the amount that can be transferred via the wire
      47             :  * method.  For example, Taler may support 0.000001 EUR as a unit of
      48             :  * payment, but SEPA only supports 0.01 EUR.  This function would
      49             :  * round 0.125 EUR to 0.12 EUR in this case.
      50             :  *
      51             :  * @param cls the @e cls of this struct with the plugin-specific state
      52             :  * @param[in,out] amount amount to round down
      53             :  * @return #GNUNET_OK on success, #GNUNET_NO if rounding was unnecessary,
      54             :  *         #GNUNET_SYSERR if the amount or currency was invalid
      55             :  */
      56             : static int
      57           3 : sepa_amount_round (void *cls,
      58             :                    struct TALER_Amount *amount)
      59             : {
      60           3 :   struct SepaClosure *sc = cls;
      61             :   uint32_t delta;
      62             : 
      63           3 :   if (NULL == sc->currency)
      64           0 :     return GNUNET_SYSERR;
      65           3 :   if (0 != strcasecmp (amount->currency,
      66           3 :                        sc->currency))
      67             :   {
      68           1 :     GNUNET_break (0);
      69           1 :     return GNUNET_SYSERR;
      70             :   }
      71           2 :   delta = amount->fraction % (TALER_AMOUNT_FRAC_BASE / 100);
      72           2 :   if (0 == delta)
      73           1 :     return GNUNET_NO;
      74           1 :   amount->fraction -= delta;
      75           1 :   return GNUNET_OK;
      76             : }
      77             : 
      78             : 
      79             : /* Taken from GNU gettext */
      80             : 
      81             : /**
      82             :  * Entry in the country table.
      83             :  */
      84             : struct table_entry
      85             : {
      86             :   /**
      87             :    * 2-Character international country code.
      88             :    */
      89             :   const char *code;
      90             : 
      91             :   /**
      92             :    * Long English name of the country.
      93             :    */
      94             :   const char *english;
      95             : };
      96             : 
      97             : 
      98             : /* Keep the following table in sync with gettext.
      99             :    WARNING: the entries should stay sorted according to the code */
     100             : /**
     101             :  * List of country codes.
     102             :  */
     103             : static const struct table_entry country_table[] =
     104             :   {
     105             :     { "AE", "U.A.E." },
     106             :     { "AF", "Afghanistan" },
     107             :     { "AL", "Albania" },
     108             :     { "AM", "Armenia" },
     109             :     { "AN", "Netherlands Antilles" },
     110             :     { "AR", "Argentina" },
     111             :     { "AT", "Austria" },
     112             :     { "AU", "Australia" },
     113             :     { "AZ", "Azerbaijan" },
     114             :     { "BA", "Bosnia and Herzegovina" },
     115             :     { "BD", "Bangladesh" },
     116             :     { "BE", "Belgium" },
     117             :     { "BG", "Bulgaria" },
     118             :     { "BH", "Bahrain" },
     119             :     { "BN", "Brunei Darussalam" },
     120             :     { "BO", "Bolivia" },
     121             :     { "BR", "Brazil" },
     122             :     { "BT", "Bhutan" },
     123             :     { "BY", "Belarus" },
     124             :     { "BZ", "Belize" },
     125             :     { "CA", "Canada" },
     126             :     { "CG", "Congo" },
     127             :     { "CH", "Switzerland" },
     128             :     { "CI", "Cote d'Ivoire" },
     129             :     { "CL", "Chile" },
     130             :     { "CM", "Cameroon" },
     131             :     { "CN", "People's Republic of China" },
     132             :     { "CO", "Colombia" },
     133             :     { "CR", "Costa Rica" },
     134             :     { "CS", "Serbia and Montenegro" },
     135             :     { "CZ", "Czech Republic" },
     136             :     { "DE", "Germany" },
     137             :     { "DK", "Denmark" },
     138             :     { "DO", "Dominican Republic" },
     139             :     { "DZ", "Algeria" },
     140             :     { "EC", "Ecuador" },
     141             :     { "EE", "Estonia" },
     142             :     { "EG", "Egypt" },
     143             :     { "ER", "Eritrea" },
     144             :     { "ES", "Spain" },
     145             :     { "ET", "Ethiopia" },
     146             :     { "FI", "Finland" },
     147             :     { "FO", "Faroe Islands" },
     148             :     { "FR", "France" },
     149             :     { "GB", "United Kingdom" },
     150             :     { "GD", "Caribbean" },
     151             :     { "GE", "Georgia" },
     152             :     { "GL", "Greenland" },
     153             :     { "GR", "Greece" },
     154             :     { "GT", "Guatemala" },
     155             :     { "HK", "Hong Kong" },
     156             :     { "HK", "Hong Kong S.A.R." },
     157             :     { "HN", "Honduras" },
     158             :     { "HR", "Croatia" },
     159             :     { "HT", "Haiti" },
     160             :     { "HU", "Hungary" },
     161             :     { "ID", "Indonesia" },
     162             :     { "IE", "Ireland" },
     163             :     { "IL", "Israel" },
     164             :     { "IN", "India" },
     165             :     { "IQ", "Iraq" },
     166             :     { "IR", "Iran" },
     167             :     { "IS", "Iceland" },
     168             :     { "IT", "Italy" },
     169             :     { "JM", "Jamaica" },
     170             :     { "JO", "Jordan" },
     171             :     { "JP", "Japan" },
     172             :     { "KE", "Kenya" },
     173             :     { "KG", "Kyrgyzstan" },
     174             :     { "KH", "Cambodia" },
     175             :     { "KR", "South Korea" },
     176             :     { "KW", "Kuwait" },
     177             :     { "KZ", "Kazakhstan" },
     178             :     { "LA", "Laos" },
     179             :     { "LB", "Lebanon" },
     180             :     { "LI", "Liechtenstein" },
     181             :     { "LK", "Sri Lanka" },
     182             :     { "LT", "Lithuania" },
     183             :     { "LU", "Luxembourg" },
     184             :     { "LV", "Latvia" },
     185             :     { "LY", "Libya" },
     186             :     { "MA", "Morocco" },
     187             :     { "MC", "Principality of Monaco" },
     188             :     { "MD", "Moldava" },
     189             :     { "MD", "Moldova" },
     190             :     { "ME", "Montenegro" },
     191             :     { "MK", "Former Yugoslav Republic of Macedonia" },
     192             :     { "ML", "Mali" },
     193             :     { "MM", "Myanmar" },
     194             :     { "MN", "Mongolia" },
     195             :     { "MO", "Macau S.A.R." },
     196             :     { "MT", "Malta" },
     197             :     { "MV", "Maldives" },
     198             :     { "MX", "Mexico" },
     199             :     { "MY", "Malaysia" },
     200             :     { "NG", "Nigeria" },
     201             :     { "NI", "Nicaragua" },
     202             :     { "NL", "Netherlands" },
     203             :     { "NO", "Norway" },
     204             :     { "NP", "Nepal" },
     205             :     { "NZ", "New Zealand" },
     206             :     { "OM", "Oman" },
     207             :     { "PA", "Panama" },
     208             :     { "PE", "Peru" },
     209             :     { "PH", "Philippines" },
     210             :     { "PK", "Islamic Republic of Pakistan" },
     211             :     { "PL", "Poland" },
     212             :     { "PR", "Puerto Rico" },
     213             :     { "PT", "Portugal" },
     214             :     { "PY", "Paraguay" },
     215             :     { "QA", "Qatar" },
     216             :     { "RE", "Reunion" },
     217             :     { "RO", "Romania" },
     218             :     { "RS", "Serbia" },
     219             :     { "RU", "Russia" },
     220             :     { "RW", "Rwanda" },
     221             :     { "SA", "Saudi Arabia" },
     222             :     { "SE", "Sweden" },
     223             :     { "SG", "Singapore" },
     224             :     { "SI", "Slovenia" },
     225             :     { "SK", "Slovak" },
     226             :     { "SN", "Senegal" },
     227             :     { "SO", "Somalia" },
     228             :     { "SR", "Suriname" },
     229             :     { "SV", "El Salvador" },
     230             :     { "SY", "Syria" },
     231             :     { "TH", "Thailand" },
     232             :     { "TJ", "Tajikistan" },
     233             :     { "TM", "Turkmenistan" },
     234             :     { "TN", "Tunisia" },
     235             :     { "TR", "Turkey" },
     236             :     { "TT", "Trinidad and Tobago" },
     237             :     { "TW", "Taiwan" },
     238             :     { "TZ", "Tanzania" },
     239             :     { "UA", "Ukraine" },
     240             :     { "US", "United States" },
     241             :     { "UY", "Uruguay" },
     242             :     { "VA", "Vatican" },
     243             :     { "VE", "Venezuela" },
     244             :     { "VN", "Viet Nam" },
     245             :     { "YE", "Yemen" },
     246             :     { "ZA", "South Africa" },
     247             :     { "ZW", "Zimbabwe" }
     248             :   };
     249             : 
     250             : 
     251             : /**
     252             :  * Country code comparator function, for binary search with bsearch().
     253             :  *
     254             :  * @param ptr1 pointer to a `struct table_entry`
     255             :  * @param ptr2 pointer to a `struct table_entry`
     256             :  * @return result of strncmp()'ing the 2-digit country codes of the entries
     257             :  */
     258             : static int
     259          67 : cmp_country_code (const void *ptr1,
     260             :                   const void *ptr2)
     261             : {
     262          67 :   const struct table_entry *cc1 = ptr1;
     263          67 :   const struct table_entry *cc2 = ptr2;
     264             : 
     265          67 :   return strncmp (cc1->code,
     266             :                   cc2->code,
     267             :                   2);
     268             : }
     269             : 
     270             : 
     271             : /**
     272             :  * Validates given IBAN according to the European Banking Standards.  See:
     273             :  * http://www.europeanpaymentscouncil.eu/documents/ECBS%20IBAN%20standard%20EBS204_V3.2.pdf
     274             :  *
     275             :  * @param iban the IBAN number to validate
     276             :  * @return #GNUNET_YES if correctly formatted; #GNUNET_NO if not
     277             :  */
     278             : static int
     279          13 : validate_iban (const char *iban)
     280             : {
     281             :   char cc[2];
     282             :   char ibancpy[35];
     283             :   struct table_entry cc_entry;
     284             :   unsigned int len;
     285             :   char *nbuf;
     286             :   unsigned int i;
     287             :   unsigned int j;
     288             :   unsigned long long dividend;
     289             :   unsigned long long remainder;
     290             :   int nread;
     291             :   int ret;
     292             : 
     293          13 :   len = strlen (iban);
     294          13 :   if (len > 34)
     295             :   {
     296           0 :     GNUNET_break_op (0);
     297           0 :     return GNUNET_NO;
     298             :   }
     299          13 :   strncpy (cc, iban, 2);
     300          13 :   strncpy (ibancpy, iban + 4, len - 4);
     301          13 :   strncpy (ibancpy + len - 4, iban, 4);
     302          13 :   ibancpy[len] = '\0';
     303          13 :   cc_entry.code = cc;
     304          13 :   cc_entry.english = NULL;
     305          13 :   if (NULL ==
     306          13 :       bsearch (&cc_entry,
     307             :                country_table,
     308             :                sizeof (country_table) / sizeof (struct table_entry),
     309             :                sizeof (struct table_entry),
     310             :                &cmp_country_code))
     311             :   {
     312           1 :     GNUNET_break_op (0);
     313           1 :     return GNUNET_NO;
     314             :   }
     315          12 :   nbuf = GNUNET_malloc ((len * 2) + 1);
     316         276 :   for (i=0, j=0; i < len; i++)
     317             :   {
     318         264 :     if (isalpha ((unsigned char) ibancpy[i]))
     319             :     {
     320          24 :       if (2 != snprintf(&nbuf[j],
     321             :                         3,
     322             :                         "%2u",
     323          24 :                         (ibancpy[i] - 'A' + 10)))
     324             :       {
     325           0 :         GNUNET_free (nbuf);
     326           0 :         return GNUNET_NO;
     327             :       }
     328          24 :       j += 2;
     329          24 :       continue;
     330             :     }
     331         240 :     nbuf[j] = ibancpy[i];
     332         240 :     j++;
     333             :   }
     334         300 :   for (j=0;'\0' != nbuf[j];j++)
     335         288 :     GNUNET_assert (isdigit( (unsigned char) nbuf[j]));
     336             :   GNUNET_assert (sizeof(dividend) >= 8);
     337          12 :   remainder = 0;
     338          36 :   for (i=0; i<j; i+=16)
     339             :   {
     340          24 :     if (1 !=
     341          24 :         (ret = sscanf (&nbuf[i],
     342             :                        "%16llu %n",
     343             :                        &dividend,
     344             :                        &nread)))
     345             :     {
     346           0 :       GNUNET_free (nbuf);
     347           0 :       GNUNET_break_op (0);
     348           0 :       return GNUNET_NO;
     349             :     }
     350          24 :     if (0 != remainder)
     351          12 :       dividend += remainder * (pow (10, nread));
     352          24 :     remainder = dividend % 97;
     353             :   }
     354          12 :   GNUNET_free (nbuf);
     355          12 :   if (1 == remainder)
     356          11 :     return GNUNET_YES;
     357           1 :   GNUNET_break_op (0); /* checksum wrong */
     358           1 :   return GNUNET_NO;
     359             : }
     360             : 
     361             : 
     362             : /**
     363             :  * Compute purpose for signing.
     364             :  *
     365             :  * @param sepa_name name of the account holder
     366             :  * @param iban bank account number in IBAN format
     367             :  * @param bic bank identifier
     368             :  * @param[out] wsd purpose to be signed
     369             :  */
     370             : static void
     371           7 : compute_purpose (const char *sepa_name,
     372             :                  const char *iban,
     373             :                  const char *bic,
     374             :                  struct TALER_MasterWireDetailsPS *wsd)
     375             : {
     376             :   struct GNUNET_HashContext *hc;
     377             : 
     378           7 :   wsd->purpose.size = htonl (sizeof (struct TALER_MasterWireDetailsPS));
     379           7 :   wsd->purpose.purpose = htonl (TALER_SIGNATURE_MASTER_SEPA_DETAILS);
     380           7 :   hc = GNUNET_CRYPTO_hash_context_start ();
     381           7 :   GNUNET_CRYPTO_hash_context_read (hc,
     382             :                                    "sepa",
     383             :                                    strlen ("sepa") + 1);
     384           7 :   GNUNET_CRYPTO_hash_context_read (hc,
     385             :                                    sepa_name,
     386           7 :                                    strlen (sepa_name) + 1);
     387           7 :   GNUNET_CRYPTO_hash_context_read (hc,
     388             :                                    iban,
     389           7 :                                    strlen (iban) + 1);
     390           7 :   GNUNET_CRYPTO_hash_context_read (hc,
     391             :                                    bic,
     392           7 :                                    strlen (bic) + 1);
     393           7 :   GNUNET_CRYPTO_hash_context_finish (hc,
     394             :                                      &wsd->h_sepa_details);
     395           7 : }
     396             : 
     397             : 
     398             : /**
     399             :  * Verify that the signature in the @a json for /wire/sepa is valid.
     400             :  *
     401             :  * @param json json reply with the signature
     402             :  * @param master_pub public key of the exchange to verify against
     403             :  * @return #GNUNET_SYSERR if @a json is invalid,
     404             :  *         #GNUNET_NO if the method is unknown,
     405             :  *         #GNUNET_OK if the json is valid
     406             :  */
     407             : static int
     408          10 : verify_wire_sepa_signature_ok (const json_t *json,
     409             :                                const struct TALER_MasterPublicKeyP *master_pub)
     410             : {
     411             :   struct TALER_MasterSignatureP exchange_sig;
     412             :   struct TALER_MasterWireDetailsPS mp;
     413             :   const char *name;
     414             :   const char *iban;
     415             :   const char *bic;
     416          10 :   struct GNUNET_JSON_Specification spec[] = {
     417             :     GNUNET_JSON_spec_fixed_auto ("sig", &exchange_sig),
     418             :     GNUNET_JSON_spec_string ("name", &name),
     419             :     GNUNET_JSON_spec_string ("iban", &iban),
     420             :     GNUNET_JSON_spec_string ("bic", &bic),
     421             :     GNUNET_JSON_spec_end()
     422             :   };
     423             : 
     424          10 :   if (NULL == master_pub)
     425             :   {
     426           4 :     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     427             :                 "Skipping signature check as master public key not given\n");
     428           4 :     return GNUNET_OK;
     429             :   }
     430           6 :   if (GNUNET_OK !=
     431           6 :       GNUNET_JSON_parse (json, spec,
     432             :                          NULL, NULL))
     433             :   {
     434           0 :     GNUNET_break_op (0);
     435           0 :     return GNUNET_SYSERR;
     436             :   }
     437           6 :   compute_purpose (name,
     438             :                    iban,
     439             :                    bic,
     440             :                    &mp);
     441           6 :   if (GNUNET_OK !=
     442           6 :       GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_SEPA_DETAILS,
     443             :                                   &mp.purpose,
     444             :                                   &exchange_sig.eddsa_signature,
     445             :                                   &master_pub->eddsa_pub))
     446             :   {
     447           0 :     GNUNET_break_op (0);
     448           0 :     GNUNET_JSON_parse_free (spec);
     449           0 :     return GNUNET_SYSERR;
     450             :   }
     451           6 :   GNUNET_JSON_parse_free (spec);
     452           6 :   return GNUNET_OK;
     453             : }
     454             : 
     455             : 
     456             : /**
     457             :  * Check if the given wire format JSON object is correctly formatted
     458             :  *
     459             :  * @param cls the @e cls of this struct with the plugin-specific state
     460             :  * @param wire the JSON wire format object
     461             :  * @param master_pub public key of the exchange to verify against
     462             :  * @param[out] emsg set to an error message, unless we return #TALER_EC_NONE;
     463             :  *             error message must be freed by the caller using GNUNET_free()
     464             :  * @return #TALER_EC_NONE if correctly formatted
     465             :  */
     466             : static enum TALER_ErrorCode
     467          13 : sepa_wire_validate (void *cls,
     468             :                     const json_t *wire,
     469             :                     const struct TALER_MasterPublicKeyP *master_pub,
     470             :                     char **emsg)
     471             : {
     472             :   json_error_t error;
     473             :   const char *type;
     474             :   const char *iban;
     475             :   const char *name;
     476             :   const char *bic;
     477             : 
     478          13 :   *emsg = NULL;
     479          13 :   if (0 != json_unpack_ex
     480             :       ((json_t *) wire,
     481             :        &error, 0,
     482             :        "{"
     483             :        "s:s," /* type: sepa */
     484             :        "s:s," /* iban: IBAN */
     485             :        "s:s," /* name: beneficiary name */
     486             :        "s:s" /* bic: beneficiary bank's BIC */
     487             :        "}",
     488             :        "type", &type,
     489             :        "iban", &iban,
     490             :        "name", &name,
     491             :        "bic", &bic))
     492             :   {
     493             :     char *dump;
     494             : 
     495           0 :     dump = json_dumps (wire, 0);
     496           0 :     GNUNET_asprintf (emsg,
     497             :                      "JSON parsing failed at %s:%u: %s (%s): %s\n",
     498             :                      __FILE__, __LINE__,
     499             :                      error.text,
     500             :                      error.source,
     501             :                      dump);
     502           0 :     free (dump);
     503           0 :     return TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_JSON;
     504             :   }
     505          13 :   if (0 != strcasecmp (type,
     506             :                        "sepa"))
     507             :   {
     508           1 :     GNUNET_asprintf (emsg,
     509             :                      "Transfer type `%s' invalid for SEPA wire plugin\n",
     510             :                      type);
     511           1 :     return TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_TYPE;
     512             :   }
     513          12 :   if (1 != validate_iban (iban))
     514             :   {
     515           2 :     GNUNET_asprintf (emsg,
     516             :                      "IBAN `%s' invalid\n",
     517             :                      iban);
     518           2 :     return TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_ACCOUNT_NUMBER;
     519             :   }
     520             :   /* FIXME: don't parse again, integrate properly... */
     521          10 :   if (GNUNET_OK !=
     522          10 :       verify_wire_sepa_signature_ok (wire,
     523             :                                      master_pub))
     524             :   {
     525           0 :     GNUNET_asprintf (emsg,
     526             :                      "Signature using public key `%s' invalid\n",
     527             :                      TALER_B2S (master_pub));
     528           0 :     return TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_SIGNATURE;
     529             :   }
     530          10 :   return TALER_EC_NONE;
     531             : }
     532             : 
     533             : 
     534             : /**
     535             :  * Obtain wire transfer details in the plugin-specific format
     536             :  * from the configuration.
     537             :  *
     538             :  * @param cls closure
     539             :  * @param cfg configuration with details about wire accounts
     540             :  * @param account_name which section in the configuration should we parse
     541             :  * @return NULL if @a cfg fails to have valid wire details for @a account_name
     542             :  */
     543             : static json_t *
     544           3 : sepa_get_wire_details (void *cls,
     545             :                        const struct GNUNET_CONFIGURATION_Handle *cfg,
     546             :                        const char *account_name)
     547             : {
     548             :   char *sepa_wire_file;
     549             :   json_error_t err;
     550             :   json_t *ret;
     551             :   char *emsg;
     552             : 
     553             :   /* Fetch reply */
     554           3 :   if (GNUNET_OK !=
     555           3 :       GNUNET_CONFIGURATION_get_value_filename (cfg,
     556             :                                                account_name,
     557             :                                                "SEPA_RESPONSE_FILE",
     558             :                                                &sepa_wire_file))
     559             :   {
     560           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING,
     561             :                                account_name,
     562             :                                "SEPA_RESPONSE_FILE");
     563           0 :     return NULL;
     564             :   }
     565           3 :   ret = json_load_file (sepa_wire_file,
     566             :                         JSON_REJECT_DUPLICATES,
     567             :                         &err);
     568           3 :   if (NULL == ret)
     569             :   {
     570           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     571             :                 "Failed to parse JSON in %s: %s (%s:%u)\n",
     572             :                 sepa_wire_file,
     573             :                 err.text,
     574             :                 err.source,
     575             :                 err.line);
     576           0 :     GNUNET_free (sepa_wire_file);
     577           0 :     return NULL;
     578             :   }
     579           3 :   if (TALER_EC_NONE !=
     580           3 :       sepa_wire_validate (cls,
     581             :                           ret,
     582             :                           NULL,
     583             :                           &emsg))
     584             :     {
     585           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     586             :                 "Failed to validate SEPA data in %s: %s\n",
     587             :                 sepa_wire_file,
     588             :                 emsg);
     589           0 :     GNUNET_free (emsg);
     590           0 :     GNUNET_free (sepa_wire_file);
     591           0 :     json_decref (ret);
     592           0 :     return NULL;
     593             :   }
     594           3 :   GNUNET_free (sepa_wire_file);
     595           3 :   return ret;
     596             : }
     597             : 
     598             : 
     599             : /**
     600             :  * Sign wire transfer details in the plugin-specific format.
     601             :  *
     602             :  * @param cls closure
     603             :  * @param in wire transfer details in JSON format
     604             :  * @param key private signing key to use
     605             :  * @param salt salt to add
     606             :  * @param[out] sig where to write the signature
     607             :  * @return #GNUNET_OK on success
     608             :  */
     609             : static int
     610           1 : sepa_sign_wire_details (void *cls,
     611             :                         const json_t *in,
     612             :                         const struct TALER_MasterPrivateKeyP *key,
     613             :                         const struct GNUNET_HashCode *salt,
     614             :                         struct TALER_MasterSignatureP *sig)
     615             : {
     616             :   struct TALER_MasterWireDetailsPS wsd;
     617             :   const char *sepa_name;
     618             :   const char *iban;
     619             :   const char *bic;
     620             :   const char *type;
     621             :   json_error_t err;
     622             : 
     623           1 :   if (0 !=
     624           1 :       json_unpack_ex ((json_t *) in,
     625             :                       &err,
     626             :                       0 /* flags */,
     627             :                       "{s:s, s:s, s:s, s:s}",
     628             :                       "type", &type,
     629             :                       "name", &sepa_name,
     630             :                       "iban", &iban,
     631             :                       "bic", &bic))
     632             :   {
     633           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     634             :                 "Failed to unpack JSON: %s (at %u)\n",
     635             :                 err.text,
     636             :                 err.position);
     637           0 :     return GNUNET_SYSERR;
     638             :   }
     639           1 :   if (0 != strcmp (type,
     640             :                    "sepa"))
     641             :   {
     642           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     643             :                 "`type' must be `sepa' for SEPA wire details\n");
     644           0 :     return GNUNET_SYSERR;
     645             :   }
     646           1 :   if (1 != validate_iban (iban))
     647             :   {
     648           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     649             :                 "IBAN invalid in SEPA wire details\n");
     650           0 :     return GNUNET_SYSERR;
     651             :   }
     652           1 :   compute_purpose (sepa_name,
     653             :                    iban,
     654             :                    bic,
     655             :                    &wsd);
     656           1 :   GNUNET_CRYPTO_eddsa_sign (&key->eddsa_priv,
     657             :                             &wsd.purpose,
     658             :                             &sig->eddsa_signature);
     659           1 :   return GNUNET_OK;
     660             : }
     661             : 
     662             : 
     663             : /**
     664             :  * Prepare for exeuction of a wire transfer.
     665             :  *
     666             :  * @param cls the @e cls of this struct with the plugin-specific state
     667             :  * @param wire valid wire account information
     668             :  * @param amount amount to transfer, already rounded
     669             :  * @param exchange_base_url base URL of the exchange (for tracking)
     670             :  * @param wtid wire transfer identifier to use
     671             :  *(@paremxsc fqnCtion to call with the prepared data to persist
     672             :  * @param psc_cls closure for @a psc
     673             :  * @return NULL on failure
     674             :  */
     675             : static struct TALER_WIRE_PrepareHandle *
     676           0 : sepa_prepare_wire_transfer (void *cls,
     677             :                             const json_t *wire,
     678             :                             const struct TALER_Amount *amount,
     679             :                             const char *exchange_base_url,
     680             :                             const struct TALER_WireTransferIdentifierRawP *wtid,
     681             :                             TALER_WIRE_PrepareTransactionCallback psc,
     682             :                             void *psc_cls)
     683             : {
     684           0 :   GNUNET_break (0); // FIXME: not implemented
     685           0 :   return NULL;
     686             : }
     687             : 
     688             : 
     689             : /**
     690             :  * Abort preparation of a wire transfer. For example,
     691             :  * because we are shutting down.
     692             :  *
     693             :  * @param cls the @e cls of this struct with the plugin-specific state
     694             :  * @param pth preparation to cancel
     695             :  */
     696             : static void
     697           0 : sepa_prepare_wire_transfer_cancel (void *cls,
     698             :                                    struct TALER_WIRE_PrepareHandle *pth)
     699             : {
     700           0 :   GNUNET_break (0); // FIXME: not implemented
     701           0 : }
     702             : 
     703             : 
     704             : /**
     705             :  * Execute a wire transfer.
     706             :  *
     707             :  * @param cls the @e cls of this struct with the plugin-specific state
     708             :  * @param buf buffer with the prepared execution details
     709             :  * @param buf_size number of bytes in @a buf
     710             :  * @param cc function to call upon success
     711             :  * @param cc_cls closure for @a cc
     712             :  * @return NULL on error
     713             :  */
     714             : static struct TALER_WIRE_ExecuteHandle *
     715           0 : sepa_execute_wire_transfer (void *cls,
     716             :                             const char *buf,
     717             :                             size_t buf_size,
     718             :                             TALER_WIRE_ConfirmationCallback cc,
     719             :                             void *cc_cls)
     720             : {
     721           0 :   GNUNET_break (0); // FIXME: not implemented
     722           0 :   return NULL;
     723             : }
     724             : 
     725             : 
     726             : /**
     727             :  * Abort execution of a wire transfer. For example, because we are
     728             :  * shutting down.  Note that if an execution is aborted, it may or
     729             :  * may not still succeed. The caller MUST run @e
     730             :  * execute_wire_transfer again for the same request as soon as
     731             :  * possilbe, to ensure that the request either ultimately succeeds
     732             :  * or ultimately fails. Until this has been done, the transaction is
     733             :  * in limbo (i.e. may or may not have been committed).
     734             :  *
     735             :  * @param cls the @e cls of this struct with the plugin-specific state
     736             :  * @param eh execution to cancel
     737             :  */
     738             : static void
     739           0 : sepa_execute_wire_transfer_cancel (void *cls,
     740             :                                    struct TALER_WIRE_ExecuteHandle *eh)
     741             : {
     742           0 :   GNUNET_break (0); // FIXME: not implemented
     743           0 : }
     744             : 
     745             : 
     746             : /**
     747             :  * Query transfer history of an account.  We use the variable-size
     748             :  * @a start_off to indicate which transfers we are interested in as
     749             :  * different banking systems may have different ways to identify
     750             :  * transfers.  The @a start_off value must thus match the value of
     751             :  * a `row_off` argument previously given to the @a hres_cb.  Use
     752             :  * NULL to query transfers from the beginning of time (with
     753             :  * positive @a num_results) or from the latest committed transfers
     754             :  * (with negative @a num_results).
     755             :  *
     756             :  * @param cls the @e cls of this struct with the plugin-specific state
     757             :  * @param direction what kinds of wire transfers should be returned
     758             :  * @param start_off from which row on do we want to get results, use NULL for the latest; exclusive
     759             :  * @param start_off_len number of bytes in @a start_off; must be `sizeof(uint64_t)`.
     760             :  * @param num_results how many results do we want; negative numbers to go into the past,
     761             :  *                    positive numbers to go into the future starting at @a start_row;
     762             :  *                    must not be zero.
     763             :  * @param hres_cb the callback to call with the transaction history
     764             :  * @param hres_cb_cls closure for the above callback
     765             :  */
     766             : static struct TALER_WIRE_HistoryHandle *
     767           0 : sepa_get_history (void *cls,
     768             :                   enum TALER_BANK_Direction direction,
     769             :                   const void *start_off,
     770             :                   size_t start_off_len,
     771             :                   int64_t num_results,
     772             :                   TALER_WIRE_HistoryResultCallback hres_cb,
     773             :                   void *hres_cb_cls)
     774             : {
     775           0 :   GNUNET_break (0);
     776           0 :   return NULL;
     777             : }
     778             : 
     779             : 
     780             : /**
     781             :  * Cancel going over the account's history.
     782             :  *
     783             :  * @param cls the @e cls of this struct with the plugin-specific state
     784             :  * @param whh operation to cancel
     785             :  */
     786             : static void
     787           0 : sepa_get_history_cancel (void *cls,
     788             :                          struct TALER_WIRE_HistoryHandle *whh)
     789             : {
     790           0 :   GNUNET_break (0);
     791           0 : }
     792             : 
     793             : 
     794             : 
     795             : /**
     796             :  * Context for a rejection operation.
     797             :  */
     798             : struct TALER_WIRE_RejectHandle
     799             : {
     800             :   /**
     801             :    * Function to call with the result.
     802             :    */
     803             :   TALER_WIRE_RejectTransferCallback rej_cb;
     804             : 
     805             :   /**
     806             :    * Closure for @e rej_cb.
     807             :    */
     808             :   void *rej_cb_cls;
     809             : 
     810             :   /**
     811             :    * Handle to task for timeout of operation.
     812             :    */
     813             :   struct GNUNET_SCHEDULER_Task *timeout_task;
     814             : };
     815             : 
     816             : 
     817             : /**
     818             :  * Rejection operation failed with timeout, notify callback
     819             :  * and clean up.
     820             :  *
     821             :  * @param cls closure with `struct TALER_WIRE_RejectHandle`
     822             :  */
     823             : static void
     824           0 : timeout_reject (void *cls)
     825             : {
     826           0 :   struct TALER_WIRE_RejectHandle *rh = cls;
     827             : 
     828           0 :   rh->timeout_task = NULL;
     829           0 :   rh->rej_cb (rh->rej_cb_cls,
     830             :               TALER_EC_NOT_IMPLEMENTED /* in the future: TALER_EC_TIMEOUT */);
     831           0 :   GNUNET_free (rh);
     832           0 : }
     833             : 
     834             : 
     835             : /**
     836             :  * Reject an incoming wire transfer that was obtained from the
     837             :  * history. This function can be used to transfer funds back to
     838             :  * the sender if the WTID was malformed (i.e. due to a typo).
     839             :  *
     840             :  * Calling `reject_transfer` twice on the same wire transfer should
     841             :  * be idempotent, i.e. not cause the funds to be wired back twice.
     842             :  * Furthermore, the transfer should henceforth be removed from the
     843             :  * results returned by @e get_history.
     844             :  *
     845             :  * @param cls plugin's closure
     846             :  * @param start_off offset of the wire transfer in plugin-specific format
     847             :  * @param start_off_len number of bytes in @a start_off
     848             :  * @param rej_cb function to call with the result of the operation
     849             :  * @param rej_cb_cls closure for @a rej_cb
     850             :  * @return handle to cancel the operation
     851             :  */
     852             : static struct TALER_WIRE_RejectHandle *
     853           0 : sepa_reject_transfer (void *cls,
     854             :                       const void *start_off,
     855             :                       size_t start_off_len,
     856             :                       TALER_WIRE_RejectTransferCallback rej_cb,
     857             :                       void *rej_cb_cls)
     858             : {
     859             :   struct TALER_WIRE_RejectHandle *rh;
     860             : 
     861           0 :   GNUNET_break (0); /* not implemented, just a stub! */
     862           0 :   rh = GNUNET_new (struct TALER_WIRE_RejectHandle);
     863           0 :   rh->rej_cb = rej_cb;
     864           0 :   rh->rej_cb_cls = rej_cb_cls;
     865           0 :   rh->timeout_task = GNUNET_SCHEDULER_add_now (&timeout_reject,
     866             :                                                rh);
     867           0 :   return rh;
     868             : }
     869             : 
     870             : 
     871             : /**
     872             :  * Cancel ongoing reject operation.  Note that the rejection may still
     873             :  * proceed. Basically, if this function is called, the rejection may
     874             :  * have happened or not.  This function is usually used during shutdown
     875             :  * or system upgrades.  At a later point, the application must call
     876             :  * @e reject_transfer again for this wire transfer, unless the
     877             :  * @e get_history shows that the wire transfer no longer exists.
     878             :  *
     879             :  * @param cls plugins' closure
     880             :  * @param rh operation to cancel
     881             :  * @return closure of the callback of the operation
     882             :  */
     883             : static void *
     884           0 : sepa_reject_transfer_cancel (void *cls,
     885             :                              struct TALER_WIRE_RejectHandle *rh)
     886             : {
     887           0 :   void *ret = rh->rej_cb_cls;
     888             : 
     889           0 :   GNUNET_SCHEDULER_cancel (rh->timeout_task);
     890           0 :   GNUNET_free (rh);
     891           0 :   return ret;
     892             : }
     893             : 
     894             : 
     895             : /**
     896             :  * Initialize sepa-wire subsystem.
     897             :  *
     898             :  * @param cls a configuration instance
     899             :  * @return NULL on error, otherwise a `struct TALER_WIRE_Plugin`
     900             :  */
     901             : void *
     902           6 : libtaler_plugin_wire_sepa_init (void *cls)
     903             : {
     904           6 :   struct GNUNET_CONFIGURATION_Handle *cfg = cls;
     905             :   struct SepaClosure *sc;
     906             :   struct TALER_WIRE_Plugin *plugin;
     907             : 
     908           6 :   sc = GNUNET_new (struct SepaClosure);
     909           6 :   if (NULL != cfg)
     910             :   {
     911           4 :     if (GNUNET_OK !=
     912           4 :         GNUNET_CONFIGURATION_get_value_string (cfg,
     913             :                                                "taler",
     914             :                                                "CURRENCY",
     915             :                                                &sc->currency))
     916             :     {
     917           0 :       GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     918             :                                  "taler",
     919             :                                  "CURRENCY");
     920           0 :       GNUNET_free (sc);
     921           0 :       return NULL;
     922             :     }
     923             :   }
     924           6 :   plugin = GNUNET_new (struct TALER_WIRE_Plugin);
     925           6 :   plugin->cls = sc;
     926           6 :   plugin->amount_round = &sepa_amount_round;
     927           6 :   plugin->get_wire_details = &sepa_get_wire_details;
     928           6 :   plugin->sign_wire_details = &sepa_sign_wire_details;
     929           6 :   plugin->wire_validate = &sepa_wire_validate;
     930           6 :   plugin->prepare_wire_transfer = &sepa_prepare_wire_transfer;
     931           6 :   plugin->prepare_wire_transfer_cancel = &sepa_prepare_wire_transfer_cancel;
     932           6 :   plugin->execute_wire_transfer = &sepa_execute_wire_transfer;
     933           6 :   plugin->execute_wire_transfer_cancel = &sepa_execute_wire_transfer_cancel;
     934           6 :   plugin->get_history = &sepa_get_history;
     935           6 :   plugin->get_history_cancel = &sepa_get_history_cancel;
     936           6 :   plugin->reject_transfer = &sepa_reject_transfer;
     937           6 :   plugin->reject_transfer_cancel = &sepa_reject_transfer_cancel;
     938           6 :   return plugin;
     939             : }
     940             : 
     941             : 
     942             : /**
     943             :  * Shutdown Sepa wire subsystem.
     944             :  *
     945             :  * @param cls a `struct TALER_WIRE_Plugin`
     946             :  * @return NULL (always)
     947             :  */
     948             : void *
     949           6 : libtaler_plugin_wire_sepa_done (void *cls)
     950             : {
     951           6 :   struct TALER_WIRE_Plugin *plugin = cls;
     952           6 :   struct SepaClosure *sc = plugin->cls;
     953             : 
     954           6 :   GNUNET_free_non_null (sc->currency);
     955           6 :   GNUNET_free (sc);
     956           6 :   GNUNET_free (plugin);
     957           6 :   return NULL;
     958             : }
     959             : 
     960             : /* end of plugin_wire_sepa.c */

Generated by: LCOV version 1.13