anastasis

Credential backup and recovery protocol and service
Log | Files | Refs | Submodules | README | LICENSE

anastasis-db_update_lifetime.c (6945B)


      1 /*
      2   This file is part of Anastasis
      3   Copyright (C) 2020-2022 Anastasis SARL
      4 
      5   Anastasis is free software; you can redistribute it and/or modify it under the
      6   terms of the GNU Affero General Public License as published by the Free Software
      7   Foundation; either version 3, or (at your option) any later version.
      8 
      9   Anastasis is distributed in the hope that it will be useful, but WITHOUT ANY
     10   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
     11   A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more details.
     12 
     13   You should have received a copy of the GNU Affero General Public License along with
     14   Anastasis; see the file COPYING.GPL.  If not, see <http://www.gnu.org/licenses/>
     15 */
     16 /**
     17  * @file stasis/anastasis-db_update_lifetime.c
     18  * @brief Anastasis database: update lifetime
     19  * @author Christian Grothoff
     20  */
     21 #include "platform.h"
     22 #include "anastasis-db_pg.h"
     23 #include "anastasis/anastasis-database/update_lifetime.h"
     24 #include "anastasis/anastasis-database/transaction.h"
     25 #include "anastasis/anastasis-database/preflight.h"
     26 #include <taler/taler_pq_lib.h>
     27 
     28 
     29 /**
     30  * Update account lifetime to the maximum of the current
     31  * value and @a eol.
     32  *
     33  * @param account_pub which account received a payment
     34  * @param payment_identifier proof of payment, must be unique and match pending payment
     35  * @param eol for how long is the account now paid (absolute)
     36  * @return transaction status
     37  */
     38 // FIXME: what is the significant delta to increment_lifetime?
     39 // Should we combine these?
     40 enum GNUNET_DB_QueryStatus
     41 ANASTASIS_DB_update_lifetime (
     42   const struct ANASTASIS_CRYPTO_AccountPublicKeyP *account_pub,
     43   const struct ANASTASIS_PaymentSecretP *payment_identifier,
     44   struct GNUNET_TIME_Timestamp eol)
     45 {
     46   enum GNUNET_DB_QueryStatus qs;
     47 
     48   PREPARE ("user_select4",
     49            "SELECT"
     50            " expiration_date "
     51            "FROM anastasis_user"
     52            " WHERE user_id=$1"
     53            " FOR UPDATE;");
     54   PREPARE ("user_insert4",
     55            "INSERT INTO anastasis_user "
     56            "(user_id"
     57            ",expiration_date"
     58            ") VALUES "
     59            "($1, $2);");
     60   PREPARE ("user_update4",
     61            "UPDATE anastasis_user"
     62            " SET "
     63            " expiration_date=$1"
     64            " WHERE user_id=$2;");
     65   PREPARE ("recdoc_payment_done2",
     66            "UPDATE anastasis_recdoc_payment "
     67            "SET"
     68            " paid=TRUE "
     69            "WHERE"
     70            "  payment_identifier=$1"
     71            " AND"
     72            "  user_id=$2"
     73            " AND"
     74            "  paid=FALSE;");
     75   for (unsigned int retries = 0; retries<MAX_RETRIES; retries++)
     76   {
     77     if (GNUNET_OK !=
     78         ANASTASIS_DB_start (
     79           "update lifetime"))
     80     {
     81       GNUNET_break (0);
     82       return GNUNET_DB_STATUS_HARD_ERROR;
     83     }
     84 
     85     {
     86       struct GNUNET_PQ_QueryParam params[] = {
     87         GNUNET_PQ_query_param_auto_from_type (payment_identifier),
     88         GNUNET_PQ_query_param_auto_from_type (account_pub),
     89         GNUNET_PQ_query_param_end
     90       };
     91       qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
     92                                                "recdoc_payment_done2",
     93                                                params);
     94       if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
     95         goto retry;
     96       if (0 >= qs)
     97       {
     98         /* same payment made before, or unknown, or error
     99            => no further action! */
    100         ANASTASIS_DB_rollback ();
    101         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    102                     "Payment existed, lifetime of account %s unchanged\n",
    103                     TALER_B2S (account_pub));
    104         return qs;
    105       }
    106     }
    107 
    108     {
    109       struct GNUNET_PQ_QueryParam params[] = {
    110         GNUNET_PQ_query_param_auto_from_type (account_pub),
    111         GNUNET_PQ_query_param_end
    112       };
    113       struct GNUNET_TIME_Timestamp expiration;
    114       struct GNUNET_PQ_ResultSpec rs[] = {
    115         GNUNET_PQ_result_spec_timestamp ("expiration_date",
    116                                          &expiration),
    117         GNUNET_PQ_result_spec_end
    118       };
    119 
    120       qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
    121                                                      "user_select4",
    122                                                      params,
    123                                                      rs);
    124       switch (qs)
    125       {
    126       case GNUNET_DB_STATUS_HARD_ERROR:
    127         ANASTASIS_DB_rollback ();
    128         return qs;
    129       case GNUNET_DB_STATUS_SOFT_ERROR:
    130         goto retry;
    131       case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
    132         {
    133           /* user does not exist, create new one */
    134           struct GNUNET_PQ_QueryParam iparams[] = {
    135             GNUNET_PQ_query_param_auto_from_type (account_pub),
    136             GNUNET_PQ_query_param_timestamp (&eol),
    137             GNUNET_PQ_query_param_end
    138           };
    139 
    140           GNUNET_break (! GNUNET_TIME_absolute_is_never (eol.abs_time));
    141           qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
    142                                                    "user_insert4",
    143                                                    iparams);
    144           GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    145                       "Created new account %s with expiration %s\n",
    146                       TALER_B2S (account_pub),
    147                       GNUNET_TIME_timestamp2s (eol));
    148         }
    149         break;
    150       case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
    151         {
    152           /* user exists, update expiration_date */
    153           struct GNUNET_PQ_QueryParam iparams[] = {
    154             GNUNET_PQ_query_param_timestamp (&expiration),
    155             GNUNET_PQ_query_param_auto_from_type (account_pub),
    156             GNUNET_PQ_query_param_end
    157           };
    158 
    159           expiration = GNUNET_TIME_timestamp_max (expiration,
    160                                                   eol);
    161           GNUNET_break (! GNUNET_TIME_absolute_is_never (expiration.abs_time));
    162           qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
    163                                                    "user_update4",
    164                                                    iparams);
    165           GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    166                       "Updated account %s to new expiration %s\n",
    167                       TALER_B2S (account_pub),
    168                       GNUNET_TIME_timestamp2s (expiration));
    169         }
    170         break;
    171       }
    172     }
    173 
    174     switch (qs)
    175     {
    176     case GNUNET_DB_STATUS_HARD_ERROR:
    177       ANASTASIS_DB_rollback ();
    178       return qs;
    179     case GNUNET_DB_STATUS_SOFT_ERROR:
    180       goto retry;
    181     case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
    182       GNUNET_break (0);
    183       ANASTASIS_DB_rollback ();
    184       return GNUNET_DB_STATUS_HARD_ERROR;
    185     case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
    186       break;
    187     }
    188     qs = ANASTASIS_DB_commit ();
    189     if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
    190       goto retry;
    191     if (qs < 0)
    192       return GNUNET_DB_STATUS_HARD_ERROR;
    193     return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
    194 retry:
    195     ANASTASIS_DB_rollback ();
    196   }
    197   return GNUNET_DB_STATUS_SOFT_ERROR;
    198 }
    199 
    200 
    201 /* end of anastasis-db_update_lifetime.c */