LCOV - code coverage report
Current view: top level - wire - plugin_wire_sepa.c (source / functions) Hit Total Coverage
Test: rcoverage.info Lines: 130 184 70.7 %
Date: 2017-09-17 17:24:28 Functions: 10 16 62.5 %

          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           0 :     return GNUNET_NO;
     296          13 :   strncpy (cc, iban, 2);
     297          13 :   strncpy (ibancpy, iban + 4, len - 4);
     298          13 :   strncpy (ibancpy + len - 4, iban, 4);
     299          13 :   ibancpy[len] = '\0';
     300          13 :   cc_entry.code = cc;
     301          13 :   cc_entry.english = NULL;
     302          13 :   if (NULL ==
     303          13 :       bsearch (&cc_entry,
     304             :                country_table,
     305             :                sizeof (country_table) / sizeof (struct table_entry),
     306             :                sizeof (struct table_entry),
     307             :                &cmp_country_code))
     308           1 :     return GNUNET_NO;
     309          12 :   nbuf = GNUNET_malloc ((len * 2) + 1);
     310         276 :   for (i=0, j=0; i < len; i++)
     311             :   {
     312         264 :     if (isalpha ((int) ibancpy[i]))
     313             :     {
     314          24 :       if (2 != snprintf(&nbuf[j],
     315             :                         3,
     316             :                         "%2u",
     317          24 :                         (ibancpy[i] - 'A' + 10)))
     318             :       {
     319           0 :         GNUNET_free (nbuf);
     320           0 :         return GNUNET_NO;
     321             :       }
     322          24 :       j += 2;
     323          24 :       continue;
     324             :     }
     325         240 :     nbuf[j] = ibancpy[i];
     326         240 :     j++;
     327             :   }
     328         300 :   for (j=0;'\0' != nbuf[j];j++)
     329         288 :     GNUNET_assert (isdigit(nbuf[j]));
     330             :   GNUNET_assert (sizeof(dividend) >= 8);
     331          12 :   remainder = 0;
     332          36 :   for (i=0; i<j; i+=16)
     333             :   {
     334          24 :     if (1 !=
     335          24 :         (ret = sscanf (&nbuf[i],
     336             :                        "%16llu %n",
     337             :                        &dividend,
     338             :                        &nread)))
     339             :     {
     340           0 :       GNUNET_free (nbuf);
     341           0 :       return GNUNET_NO;
     342             :     }
     343          24 :     if (0 != remainder)
     344          12 :       dividend += remainder * (pow (10, nread));
     345          24 :     remainder = dividend % 97;
     346             :   }
     347          12 :   GNUNET_free (nbuf);
     348          12 :   if (1 == remainder)
     349          11 :     return GNUNET_YES;
     350           1 :   return GNUNET_NO;
     351             : }
     352             : 
     353             : 
     354             : /**
     355             :  * Compute purpose for signing.
     356             :  *
     357             :  * @param sepa_name name of the account holder
     358             :  * @param iban bank account number in IBAN format
     359             :  * @param bic bank identifier
     360             :  * @param[out] wsd purpose to be signed
     361             :  */
     362             : static void
     363           7 : compute_purpose (const char *sepa_name,
     364             :                  const char *iban,
     365             :                  const char *bic,
     366             :                  struct TALER_MasterWireDetailsPS *wsd)
     367             : {
     368             :   struct GNUNET_HashContext *hc;
     369             : 
     370           7 :   wsd->purpose.size = htonl (sizeof (struct TALER_MasterWireDetailsPS));
     371           7 :   wsd->purpose.purpose = htonl (TALER_SIGNATURE_MASTER_SEPA_DETAILS);
     372           7 :   hc = GNUNET_CRYPTO_hash_context_start ();
     373           7 :   GNUNET_CRYPTO_hash_context_read (hc,
     374             :                                    "sepa",
     375             :                                    strlen ("sepa") + 1);
     376           7 :   GNUNET_CRYPTO_hash_context_read (hc,
     377             :                                    sepa_name,
     378           7 :                                    strlen (sepa_name) + 1);
     379           7 :   GNUNET_CRYPTO_hash_context_read (hc,
     380             :                                    iban,
     381           7 :                                    strlen (iban) + 1);
     382           7 :   GNUNET_CRYPTO_hash_context_read (hc,
     383             :                                    bic,
     384           7 :                                    strlen (bic) + 1);
     385           7 :   GNUNET_CRYPTO_hash_context_finish (hc,
     386             :                                      &wsd->h_sepa_details);
     387           7 : }
     388             : 
     389             : 
     390             : /**
     391             :  * Verify that the signature in the @a json for /wire/sepa is valid.
     392             :  *
     393             :  * @param json json reply with the signature
     394             :  * @param master_pub public key of the exchange to verify against
     395             :  * @return #GNUNET_SYSERR if @a json is invalid,
     396             :  *         #GNUNET_NO if the method is unknown,
     397             :  *         #GNUNET_OK if the json is valid
     398             :  */
     399             : static int
     400          10 : verify_wire_sepa_signature_ok (const json_t *json,
     401             :                                const struct TALER_MasterPublicKeyP *master_pub)
     402             : {
     403             :   struct TALER_MasterSignatureP exchange_sig;
     404             :   struct TALER_MasterWireDetailsPS mp;
     405             :   const char *name;
     406             :   const char *iban;
     407             :   const char *bic;
     408          10 :   struct GNUNET_JSON_Specification spec[] = {
     409             :     GNUNET_JSON_spec_fixed_auto ("sig", &exchange_sig),
     410             :     GNUNET_JSON_spec_string ("name", &name),
     411             :     GNUNET_JSON_spec_string ("iban", &iban),
     412             :     GNUNET_JSON_spec_string ("bic", &bic),
     413             :     GNUNET_JSON_spec_end()
     414             :   };
     415             : 
     416          10 :   if (NULL == master_pub)
     417             :   {
     418           4 :     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     419             :                 "Skipping signature check as master public key not given\n");
     420           4 :     return GNUNET_OK;
     421             :   }
     422           6 :   if (GNUNET_OK !=
     423           6 :       GNUNET_JSON_parse (json, spec,
     424             :                          NULL, NULL))
     425             :   {
     426           0 :     GNUNET_break_op (0);
     427           0 :     return GNUNET_SYSERR;
     428             :   }
     429           6 :   compute_purpose (name,
     430             :                    iban,
     431             :                    bic,
     432             :                    &mp);
     433           6 :   if (GNUNET_OK !=
     434           6 :       GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_SEPA_DETAILS,
     435             :                                   &mp.purpose,
     436             :                                   &exchange_sig.eddsa_signature,
     437             :                                   &master_pub->eddsa_pub))
     438             :   {
     439           0 :     GNUNET_break_op (0);
     440           0 :     GNUNET_JSON_parse_free (spec);
     441           0 :     return GNUNET_SYSERR;
     442             :   }
     443           6 :   GNUNET_JSON_parse_free (spec);
     444           6 :   return GNUNET_OK;
     445             : }
     446             : 
     447             : 
     448             : /**
     449             :  * Check if the given wire format JSON object is correctly formatted
     450             :  *
     451             :  * @param cls the @e cls of this struct with the plugin-specific state
     452             :  * @param wire the JSON wire format object
     453             :  * @param master_pub public key of the exchange to verify against
     454             :  * @param[out] emsg set to an error message, unless we return #TALER_EC_NONE;
     455             :  *             error message must be freed by the caller using GNUNET_free()
     456             :  * @return #TALER_EC_NONE if correctly formatted
     457             :  */
     458             : static enum TALER_ErrorCode
     459          13 : sepa_wire_validate (void *cls,
     460             :                     const json_t *wire,
     461             :                     const struct TALER_MasterPublicKeyP *master_pub,
     462             :                     char **emsg)
     463             : {
     464             :   json_error_t error;
     465             :   const char *type;
     466             :   const char *iban;
     467             :   const char *name;
     468             :   const char *bic;
     469             : 
     470          13 :   *emsg = NULL;
     471          13 :   if (0 != json_unpack_ex
     472             :       ((json_t *) wire,
     473             :        &error, 0,
     474             :        "{"
     475             :        "s:s," /* type: sepa */
     476             :        "s:s," /* iban: IBAN */
     477             :        "s:s," /* name: beneficiary name */
     478             :        "s:s" /* bic: beneficiary bank's BIC */
     479             :        "}",
     480             :        "type", &type,
     481             :        "iban", &iban,
     482             :        "name", &name,
     483             :        "bic", &bic))
     484             :   {
     485             :     char *dump;
     486             : 
     487           0 :     dump = json_dumps (wire, 0);
     488           0 :     GNUNET_asprintf (emsg,
     489             :                      "JSON parsing failed at %s:%u: %s (%s): %s\n",
     490             :                      __FILE__, __LINE__,
     491             :                      error.text,
     492             :                      error.source,
     493             :                      dump);
     494           0 :     free (dump);
     495           0 :     return TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_JSON;
     496             :   }
     497          13 :   if (0 != strcasecmp (type,
     498             :                        "sepa"))
     499             :   {
     500           1 :     GNUNET_asprintf (emsg,
     501             :                      "Transfer type `%s' invalid for SEPA wire plugin\n",
     502             :                      type);
     503           1 :     return TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_TYPE;
     504             :   }
     505          12 :   if (1 != validate_iban (iban))
     506             :   {
     507           2 :     GNUNET_asprintf (emsg,
     508             :                      "IBAN `%s' invalid\n",
     509             :                      iban);
     510           2 :     return TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_ACCOUNT_NUMBER;
     511             :   }
     512             :   /* FIXME: don't parse again, integrate properly... */
     513          10 :   if (GNUNET_OK !=
     514          10 :       verify_wire_sepa_signature_ok (wire,
     515             :                                      master_pub))
     516             :   {
     517           0 :     GNUNET_asprintf (emsg,
     518             :                      "Signature using public key `%s' invalid\n",
     519             :                      TALER_B2S (master_pub));
     520           0 :     return TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_SIGNATURE;
     521             :   }
     522          10 :   return TALER_EC_NONE;
     523             : }
     524             : 
     525             : 
     526             : /**
     527             :  * Obtain wire transfer details in the plugin-specific format
     528             :  * from the configuration.
     529             :  *
     530             :  * @param cls closure
     531             :  * @param cfg configuration with details about wire accounts
     532             :  * @param account_name which section in the configuration should we parse
     533             :  * @return NULL if @a cfg fails to have valid wire details for @a account_name
     534             :  */
     535             : static json_t *
     536           3 : sepa_get_wire_details (void *cls,
     537             :                        const struct GNUNET_CONFIGURATION_Handle *cfg,
     538             :                        const char *account_name)
     539             : {
     540             :   char *sepa_wire_file;
     541             :   json_error_t err;
     542             :   json_t *ret;
     543             :   char *emsg;
     544             : 
     545             :   /* Fetch reply */
     546           3 :   if (GNUNET_OK !=
     547           3 :       GNUNET_CONFIGURATION_get_value_filename (cfg,
     548             :                                                account_name,
     549             :                                                "SEPA_RESPONSE_FILE",
     550             :                                                &sepa_wire_file))
     551             :   {
     552           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING,
     553             :                                account_name,
     554             :                                "SEPA_RESPONSE_FILE");
     555           0 :     return NULL;
     556             :   }
     557           3 :   ret = json_load_file (sepa_wire_file,
     558             :                         JSON_REJECT_DUPLICATES,
     559             :                         &err);
     560           3 :   if (NULL == ret)
     561             :   {
     562           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     563             :                 "Failed to parse JSON in %s: %s (%s:%u)\n",
     564             :                 sepa_wire_file,
     565             :                 err.text,
     566             :                 err.source,
     567             :                 err.line);
     568           0 :     GNUNET_free (sepa_wire_file);
     569           0 :     return NULL;
     570             :   }
     571           3 :   if (TALER_EC_NONE !=
     572           3 :       sepa_wire_validate (cls,
     573             :                           ret,
     574             :                           NULL,
     575             :                           &emsg))
     576             :     {
     577           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     578             :                 "Failed to validate SEPA data in %s: %s\n",
     579             :                 sepa_wire_file,
     580             :                 emsg);
     581           0 :     GNUNET_free (emsg);
     582           0 :     GNUNET_free (sepa_wire_file);
     583           0 :     json_decref (ret);
     584           0 :     return NULL;
     585             :   }
     586           3 :   GNUNET_free (sepa_wire_file);
     587           3 :   return ret;
     588             : }
     589             : 
     590             : 
     591             : /**
     592             :  * Sign wire transfer details in the plugin-specific format.
     593             :  *
     594             :  * @param cls closure
     595             :  * @param in wire transfer details in JSON format
     596             :  * @param key private signing key to use
     597             :  * @param salt salt to add
     598             :  * @param[out] sig where to write the signature
     599             :  * @return #GNUNET_OK on success
     600             :  */
     601             : static int
     602           1 : sepa_sign_wire_details (void *cls,
     603             :                         const json_t *in,
     604             :                         const struct TALER_MasterPrivateKeyP *key,
     605             :                         const struct GNUNET_HashCode *salt,
     606             :                         struct TALER_MasterSignatureP *sig)
     607             : {
     608             :   struct TALER_MasterWireDetailsPS wsd;
     609             :   const char *sepa_name;
     610             :   const char *iban;
     611             :   const char *bic;
     612             :   const char *type;
     613             :   json_error_t err;
     614             : 
     615           1 :   if (0 !=
     616           1 :       json_unpack_ex ((json_t *) in,
     617             :                       &err,
     618             :                       0 /* flags */,
     619             :                       "{s:s, s:s, s:s, s:s}",
     620             :                       "type", &type,
     621             :                       "name", &sepa_name,
     622             :                       "iban", &iban,
     623             :                       "bic", &bic))
     624             :   {
     625           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     626             :                 "Failed to unpack JSON: %s (at %u)\n",
     627             :                 err.text,
     628             :                 err.position);
     629           0 :     return GNUNET_SYSERR;
     630             :   }
     631           1 :   if (0 != strcmp (type,
     632             :                    "sepa"))
     633             :   {
     634           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     635             :                 "`type' must be `sepa' for SEPA wire details\n");
     636           0 :     return GNUNET_SYSERR;
     637             :   }
     638           1 :   if (1 != validate_iban (iban))
     639             :   {
     640           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     641             :                 "IBAN invalid in SEPA wire details\n");
     642           0 :     return GNUNET_SYSERR;
     643             :   }
     644           1 :   compute_purpose (sepa_name,
     645             :                    iban,
     646             :                    bic,
     647             :                    &wsd);
     648           1 :   GNUNET_CRYPTO_eddsa_sign (&key->eddsa_priv,
     649             :                             &wsd.purpose,
     650             :                             &sig->eddsa_signature);
     651           1 :   return GNUNET_OK;
     652             : }
     653             : 
     654             : 
     655             : /**
     656             :  * Prepare for exeuction of a wire transfer.
     657             :  *
     658             :  * @param cls the @e cls of this struct with the plugin-specific state
     659             :  * @param wire valid wire account information
     660             :  * @param amount amount to transfer, already rounded
     661             :  * @param exchange_base_url base URL of the exchange (for tracking)
     662             :  * @param wtid wire transfer identifier to use
     663             :  * @param psc function to call with the prepared data to persist
     664             :  * @param psc_cls closure for @a psc
     665             :  * @return NULL on failure
     666             :  */
     667             : static struct TALER_WIRE_PrepareHandle *
     668           0 : sepa_prepare_wire_transfer (void *cls,
     669             :                             const json_t *wire,
     670             :                             const struct TALER_Amount *amount,
     671             :                             const char *exchange_base_url,
     672             :                             const struct TALER_WireTransferIdentifierRawP *wtid,
     673             :                             TALER_WIRE_PrepareTransactionCallback psc,
     674             :                             void *psc_cls)
     675             : {
     676           0 :   GNUNET_break (0); // FIXME: not implemented
     677           0 :   return NULL;
     678             : }
     679             : 
     680             : 
     681             : /**
     682             :  * Abort preparation of a wire transfer. For example,
     683             :  * because we are shutting down.
     684             :  *
     685             :  * @param cls the @e cls of this struct with the plugin-specific state
     686             :  * @param pth preparation to cancel
     687             :  */
     688             : static void
     689           0 : sepa_prepare_wire_transfer_cancel (void *cls,
     690             :                                    struct TALER_WIRE_PrepareHandle *pth)
     691             : {
     692           0 :   GNUNET_break (0); // FIXME: not implemented
     693           0 : }
     694             : 
     695             : 
     696             : /**
     697             :  * Execute a wire transfer.
     698             :  *
     699             :  * @param cls the @e cls of this struct with the plugin-specific state
     700             :  * @param buf buffer with the prepared execution details
     701             :  * @param buf_size number of bytes in @a buf
     702             :  * @param cc function to call upon success
     703             :  * @param cc_cls closure for @a cc
     704             :  * @return NULL on error
     705             :  */
     706             : static struct TALER_WIRE_ExecuteHandle *
     707           0 : sepa_execute_wire_transfer (void *cls,
     708             :                             const char *buf,
     709             :                             size_t buf_size,
     710             :                             TALER_WIRE_ConfirmationCallback cc,
     711             :                             void *cc_cls)
     712             : {
     713           0 :   GNUNET_break (0); // FIXME: not implemented
     714           0 :   return NULL;
     715             : }
     716             : 
     717             : 
     718             : /**
     719             :  * Abort execution of a wire transfer. For example, because we are
     720             :  * shutting down.  Note that if an execution is aborted, it may or
     721             :  * may not still succeed. The caller MUST run @e
     722             :  * execute_wire_transfer again for the same request as soon as
     723             :  * possilbe, to ensure that the request either ultimately succeeds
     724             :  * or ultimately fails. Until this has been done, the transaction is
     725             :  * in limbo (i.e. may or may not have been committed).
     726             :  *
     727             :  * @param cls the @e cls of this struct with the plugin-specific state
     728             :  * @param eh execution to cancel
     729             :  */
     730             : static void
     731           0 : sepa_execute_wire_transfer_cancel (void *cls,
     732             :                                    struct TALER_WIRE_ExecuteHandle *eh)
     733             : {
     734           0 :   GNUNET_break (0); // FIXME: not implemented
     735           0 : }
     736             : 
     737             : 
     738             : /**
     739             :  * Query transfer history of an account.  We use the variable-size
     740             :  * @a start_off to indicate which transfers we are interested in as
     741             :  * different banking systems may have different ways to identify
     742             :  * transfers.  The @a start_off value must thus match the value of
     743             :  * a `row_off` argument previously given to the @a hres_cb.  Use
     744             :  * NULL to query transfers from the beginning of time (with
     745             :  * positive @a num_results) or from the latest committed transfers
     746             :  * (with negative @a num_results).
     747             :  *
     748             :  * @param cls the @e cls of this struct with the plugin-specific state
     749             :  * @param direction what kinds of wire transfers should be returned
     750             :  * @param start_off from which row on do we want to get results, use NULL for the latest; exclusive
     751             :  * @param start_off_len number of bytes in @a start_off; must be `sizeof(uint64_t)`.
     752             :  * @param num_results how many results do we want; negative numbers to go into the past,
     753             :  *                    positive numbers to go into the future starting at @a start_row;
     754             :  *                    must not be zero.
     755             :  * @param hres_cb the callback to call with the transaction history
     756             :  * @param hres_cb_cls closure for the above callback
     757             :  */
     758             : static struct TALER_WIRE_HistoryHandle *
     759           0 : sepa_get_history (void *cls,
     760             :                   enum TALER_BANK_Direction direction,
     761             :                   const void *start_off,
     762             :                   size_t start_off_len,
     763             :                   int64_t num_results,
     764             :                   TALER_WIRE_HistoryResultCallback hres_cb,
     765             :                   void *hres_cb_cls)
     766             : {
     767           0 :   GNUNET_break (0);
     768           0 :   return NULL;
     769             : }
     770             : 
     771             : 
     772             : /**
     773             :  * Cancel going over the account's history.
     774             :  *
     775             :  * @param cls the @e cls of this struct with the plugin-specific state
     776             :  * @param whh operation to cancel
     777             :  */
     778             : static void
     779           0 : sepa_get_history_cancel (void *cls,
     780             :                          struct TALER_WIRE_HistoryHandle *whh)
     781             : {
     782           0 :   GNUNET_break (0);
     783           0 : }
     784             : 
     785             : 
     786             : /**
     787             :  * Initialize sepa-wire subsystem.
     788             :  *
     789             :  * @param cls a configuration instance
     790             :  * @return NULL on error, otherwise a `struct TALER_WIRE_Plugin`
     791             :  */
     792             : void *
     793           6 : libtaler_plugin_wire_sepa_init (void *cls)
     794             : {
     795           6 :   struct GNUNET_CONFIGURATION_Handle *cfg = cls;
     796             :   struct SepaClosure *sc;
     797             :   struct TALER_WIRE_Plugin *plugin;
     798             : 
     799           6 :   sc = GNUNET_new (struct SepaClosure);
     800           6 :   if (NULL != cfg)
     801             :   {
     802           4 :     if (GNUNET_OK !=
     803           4 :         GNUNET_CONFIGURATION_get_value_string (cfg,
     804             :                                                "taler",
     805             :                                                "CURRENCY",
     806             :                                                &sc->currency))
     807             :     {
     808           0 :       GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     809             :                                  "taler",
     810             :                                  "CURRENCY");
     811           0 :       GNUNET_free (sc);
     812           0 :       return NULL;
     813             :     }
     814             :   }
     815           6 :   plugin = GNUNET_new (struct TALER_WIRE_Plugin);
     816           6 :   plugin->cls = sc;
     817           6 :   plugin->amount_round = &sepa_amount_round;
     818           6 :   plugin->get_wire_details = &sepa_get_wire_details;
     819           6 :   plugin->sign_wire_details = &sepa_sign_wire_details;
     820           6 :   plugin->wire_validate = &sepa_wire_validate;
     821           6 :   plugin->prepare_wire_transfer = &sepa_prepare_wire_transfer;
     822           6 :   plugin->prepare_wire_transfer_cancel = &sepa_prepare_wire_transfer_cancel;
     823           6 :   plugin->execute_wire_transfer = &sepa_execute_wire_transfer;
     824           6 :   plugin->execute_wire_transfer_cancel = &sepa_execute_wire_transfer_cancel;
     825           6 :   plugin->get_history = &sepa_get_history;
     826           6 :   plugin->get_history_cancel = &sepa_get_history_cancel;
     827           6 :   return plugin;
     828             : }
     829             : 
     830             : 
     831             : /**
     832             :  * Shutdown Sepa wire subsystem.
     833             :  *
     834             :  * @param cls a `struct TALER_WIRE_Plugin`
     835             :  * @return NULL (always)
     836             :  */
     837             : void *
     838           6 : libtaler_plugin_wire_sepa_done (void *cls)
     839             : {
     840           6 :   struct TALER_WIRE_Plugin *plugin = cls;
     841           6 :   struct SepaClosure *sc = plugin->cls;
     842             : 
     843           6 :   GNUNET_free_non_null (sc->currency);
     844           6 :   GNUNET_free (sc);
     845           6 :   GNUNET_free (plugin);
     846           6 :   return NULL;
     847             : }
     848             : 
     849             : /* end of plugin_wire_sepa.c */

Generated by: LCOV version 1.13