gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-anastasis] branch master updated: worked on api


From: gnunet
Subject: [taler-anastasis] branch master updated: worked on api
Date: Tue, 26 Nov 2019 15:00:59 +0100

This is an automated email from the git hooks/post-receive script.

dennis-neufeld pushed a commit to branch master
in repository anastasis.

The following commit(s) were added to refs/heads/master by this push:
     new c72f9c2  worked on api
c72f9c2 is described below

commit c72f9c236e3c5ba9a92e263101aad1184b7d1339
Author: Dennis Neufeld <address@hidden>
AuthorDate: Tue Nov 26 14:00:49 2019 +0000

    worked on api
---
 src/include/anastasis_error_codes.h     |   8 +-
 src/include/anastasis_service.h         | 173 ++++++++++++-
 src/include/anastasis_testing_lib.h     |   8 +-
 src/lib/Makefile.am                     |   6 +-
 src/lib/anastasis_api_policy_lookup.c   | 267 ++++++++++++++++++++
 src/lib/anastasis_api_policy_store.c    | 424 ++++++++++++++++++++++++++++++++
 src/lib/test_anastasis_api.c            |  64 ++++-
 src/lib/testing_api_cmd_policy_lookup.c |  63 +++++
 src/lib/testing_api_cmd_policy_store.c  | 247 +++++++++++++++++++
 src/util/Makefile.am                    |   4 +-
 10 files changed, 1234 insertions(+), 30 deletions(-)

diff --git a/src/include/anastasis_error_codes.h 
b/src/include/anastasis_error_codes.h
index 0ad7f6c..114397e 100644
--- a/src/include/anastasis_error_codes.h
+++ b/src/include/anastasis_error_codes.h
@@ -1,6 +1,6 @@
 /*
    This file is part of GNUnet
-   Copyright (C) 2017 GNUnet e.V.
+   Copyright (C) 2019 GNUnet e.V.
 
    GNUnet is free software: you can redistribute it and/or modify it
    under the terms of the GNU Affero General Public License as published
@@ -44,6 +44,12 @@ enum ANASTASIS_ErrorCode
    */
   ANASTASIS_EC_NONE = 6000,
 
+  /**
+   * Special code to indicate that a non-integer error code was
+   * returned in the JSON response.
+   */
+  ANASTASIS_EC_INVALID = 6001,
+
   /**
    * The specified User was unknown
    */
diff --git a/src/include/anastasis_service.h b/src/include/anastasis_service.h
index bdb5063..89e9664 100644
--- a/src/include/anastasis_service.h
+++ b/src/include/anastasis_service.h
@@ -17,17 +17,18 @@
  * @file include/anastasis_service.h
  * @brief C interface of libanastasisrest, a C library to use merchant's HTTP 
API
  * @author Christian Grothoff
- * @author Marcello Stanisci
  * @author Dennis Neufeld
  * @author Dominik Meister
  */
 #ifndef _ANASTASIS_SERVICE_H
 #define _ANASTASIS_SERVICE_H
 
+#include <gnunet/gnunet_util_lib.h>
 #include <gnunet/gnunet_curl_lib.h>
 #include <jansson.h>
 #include "anastasis_error_codes.h"
 
+GNUNET_NETWORK_STRUCT_BEGIN
 
 /**
  * An EdDSA public key that is used to identify a user's account.
@@ -37,6 +38,16 @@ struct ANASTASIS_AccountPubP
   struct GNUNET_CRYPTO_EddsaPublicKey pub;
 };
 
+
+/**
+ * An EdDSA private key that is used to sign upload data.
+ */
+struct ANASTASIS_AccountPrivP
+{
+  struct GNUNET_CRYPTO_EddsaPrivateKey priv;
+};
+
+
 /**
  * Random identifier used to later charge a payment.
  */
@@ -47,6 +58,43 @@ struct ANASTASIS_PaymentSecretP
 
 struct ANASTASIS_SaltOperation;
 
+
+/**
+ * Data signed by the account public key of a sync client to
+ * authorize the upload of the backup.
+ */
+struct ANASTASIS_UploadSignaturePS
+{
+  /**
+   * Set to #TALER_SIGNATURE_ANASTASIS_BACKUP_UPLOAD.
+   */
+  struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
+
+  /**
+   * Hash of the previous backup, all zeros for none.
+   */
+  struct GNUNET_HashCode old_recovery_data_hash GNUNET_PACKED;
+
+  /**
+   * Hash of the new backup.
+   */
+  struct GNUNET_HashCode new_recovery_data_hash GNUNET_PACKED;
+
+};
+
+
+/**
+ * Signature made with an account's public key.
+ */
+struct ANASTASIS_AccountSignatureP
+{
+  /**
+   * We use EdDSA.
+   */
+  struct GNUNET_CRYPTO_EddsaSignature eddsa_sig;
+};
+
+
 /**
  * Salt value of an Anastasis service provider.
  */
@@ -58,6 +106,106 @@ struct ANASTASIS_Salt
   uint32_t value[8];
 };
 
+GNUNET_NETWORK_STRUCT_END
+
+
+
+/**
+ * High-level ways how an upload may conclude.
+ */
+enum ANASTASIS_UploadStatus
+{
+  /**
+   * Backup was successfully made.
+   */
+  ANASTASIS_US_SUCCESS = 0,
+
+  /**
+   * Account expired or payment was explicitly requested
+   * by the client.
+   */
+  ANASTASIS_US_PAYMENT_REQUIRED = 1,
+
+  /**
+   * Conflicting backup existed on server. Client should
+   * reconcile and try again with (using the provided
+   * recovered backup as the previous backup).
+   */
+  ANASTASIS_US_CONFLICTING_BACKUP = 2,
+
+  /**
+   * HTTP interaction failed, see HTTP status.
+   */
+  ANASTASIS_US_HTTP_ERROR = 3,
+
+  /**
+   * We had an internal error (not sure this can happen,
+   * but reserved for HTTP 400 status codes).
+   */
+  ANASTASIS_US_CLIENT_ERROR = 4,
+
+  /**
+   * Server had an internal error.
+   */
+  ANASTASIS_US_SERVER_ERROR = 5
+};
+
+
+/**
+ * Result of an upload.
+ */
+struct ANASTASIS_UploadDetails
+{
+  /**
+   * High level status of the upload operation.
+   */
+  enum ANASTASIS_UploadStatus us;
+
+  union
+  {
+
+    /**
+     * Hash of the stored recovery data, returned if
+     * @e us is #ANASTASIS_US_SUCCESS.
+     */
+    const struct GNUNET_HashCode *curr_backup_hash;
+
+    /**
+     * Previous backup. Returned if @e us is
+     * #ANASTASIS_US_CONFLICTING_BACKUP
+     */
+    struct
+    {
+      /**
+       * Hash over @e existing_backup.
+       */
+      struct GNUNET_HashCode existing_backup_hash;
+
+      /**
+       * Number of bytes in @e existing_backup.
+       */
+      size_t existing_backup_size;
+
+      /**
+       * The backup on the server, which does not match the
+       * "previous" backup expected by the client and thus
+       * needs to be decrypted, reconciled and re-uploaded.
+       */
+      const void *existing_backup;
+
+    } recovered_backup;
+
+    /**
+     * A taler://pay/-URI with a request to pay the annual fee for
+     * the service.  Returned if @e us is #ANASTASIS_US_PAYMENT_REQUIRED.
+     */
+    const char *payment_request;
+
+  } details;
+
+};
+
+
 
 typedef void
 (ANASTASIS_SaltCallback)(void *cls,
@@ -158,28 +306,37 @@ struct ANASTASIS_PolicyStoreOperation;
  */
 typedef void
 (*ANASTASIS_PolicyStoreCallback) (void *cls,
-                                  unsigned int http_status,
                                   enum ANASTASIS_ErrorCode ec,
-                                  const json_t *obj);
+                                  unsigned int http_status,
+                                  const struct ANASTASIS_UploadDetails *up);
 
 
 /**
- * Store policies
+ * Store policies, does a POST /policy/$AccountPub
  *
  * @param ctx the CURL context used to connect to the backend
  * @param backend_url backend's base URL, including final "/"
  * @param anastasis_pub public key of the user's account
- * @param refund amount to which increase the refund
+ * @param anastasis_priv private key of the user's account
+ * @param prev_recovery_data_hash hash of the privious policy update, NULL for 
the first upload ever
+ * @param recovery_data policy data to be stored
+ * @param recovery_data_size number of bytes in @a recovery_data
+ * @param payment_requested #GNUNET_YES if the client wants to pay more for 
the account now
+ * @param paymentSecretP payment identifier of last payment
  * @param cb callback processing the response from /policy
  * @param cb_cls closure for cb
+ * @return handle for the operation
  */
 struct ANASTASIS_PolicyStoreOperation *
 ANASTASIS_policy_store (struct GNUNET_CURL_Context *ctx,
                         const char *backend_url,
                         const struct
-                        ANASTASIS_AccountPubP *anastasis_pub,
-                        const void *policy_data,
-                        size_t policy_data_size,
+                        ANASTASIS_AccountPrivP *anastasis_priv,
+                        const struct 
+                        GNUNET_HashCode *prev_recovery_data_hash,
+                        const void *recovery_data,
+                        size_t recovery_data_size,
+                        int payment_requested,
                         const struct
                         ANASTASIS_PaymentSecretP *paymentSecretP,
                         ANASTASIS_PolicyStoreCallback cb,
diff --git a/src/include/anastasis_testing_lib.h 
b/src/include/anastasis_testing_lib.h
index a6657b7..655b6cf 100644
--- a/src/include/anastasis_testing_lib.h
+++ b/src/include/anastasis_testing_lib.h
@@ -101,10 +101,11 @@ TALER_TESTING_prepare_anastasis (const char 
*config_filename);
  * @param anastasis_url base URL of the anastasis serving
  *        the policy store request.
  * @param http_status expected HTTP status.
+ * @param priv private account identifier
  * @param pub account identifier
  * @param payment_id payment identifier
  * @param policy_data recovery data to post
- *
+ * @param policy_data_size size of recovery/policy data
  * @return the command
  */
 struct TALER_TESTING_Command
@@ -112,10 +113,11 @@ ANASTASIS_TESTING_cmd_policy_store (const char *label,
                                     const char *anastasis_url,
                                     unsigned int http_status,
                                     const struct
-                                    ANASTASIS_AccountPubP *pub,
+                                    ANASTASIS_AccountPrivP *priv,
                                     const struct
                                     ANASTASIS_PaymentSecretP *payment_id,
-                                    const void *policy_data);
+                                    const void *policy_data,
+                                    size_t policy_data_size);
 /**
  * Make a "policy lookup" command.
  *
diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am
index 1f41ddf..9f3f37a 100644
--- a/src/lib/Makefile.am
+++ b/src/lib/Makefile.am
@@ -20,7 +20,8 @@ libanastasistesting_la_LDFLAGS = \
 
 libanastasis_la_SOURCES = \
   anastasis_api_salt.c \
-  anastasis_api_policy.c
+  anastasis_api_policy_store.c \
+  anastasis_api_policy_lookup.c
 
 libanastasis_la_LIBADD = \
   -lmicrohttpd \
@@ -32,7 +33,8 @@ libanastasis_la_LIBADD = \
   $(XLIB)
 
 libanastasistesting_la_SOURCES = \
-  testing_api_cmd_policy.c \
+  testing_api_cmd_policy_store.c \
+  testing_api_cmd_policy_lookup.c \
   testing_api_helpers.c 
 
 libanastasistesting_la_LIBADD = \
diff --git a/src/lib/anastasis_api_policy_lookup.c 
b/src/lib/anastasis_api_policy_lookup.c
new file mode 100644
index 0000000..449f5b3
--- /dev/null
+++ b/src/lib/anastasis_api_policy_lookup.c
@@ -0,0 +1,267 @@
+/*
+  This file is part of ANASTASIS
+  Copyright (C) 2014-2019 GNUnet e.V. and INRIA
+
+  ANASTASIS is free software; you can redistribute it and/or modify
+  it under the terms of the GNU Lesser General Public License as
+  published by the Free Software Foundation; either version 2.1,
+  or (at your option) any later version.
+
+  ANASTASIS is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with ANASTASIS; see the file COPYING.LGPL.  If not,
+  see <http://www.gnu.org/licenses/>
+*/
+
+/**
+ * @file lib/anastasis_api_policy_lookup.c
+ * @brief Implementation of the /policy GET and POST
+ * @author Christian Grothoff
+ * @author Dennis Neufeld
+ * @author Dominik Meister
+ */
+#include "platform.h"
+#include <curl/curl.h>
+#include <jansson.h>
+#include <microhttpd.h> /* just for HTTP status codes */
+#include <gnunet/gnunet_util_lib.h>
+#include <gnunet/gnunet_curl_lib.h>
+#include <taler/taler_json_lib.h>
+#include <taler/taler_curl_lib.h>
+#include <taler/taler_util.h>
+#include "anastasis_service.h"
+
+
+/**
+ * @brief A Contract Operation Handle
+ */
+struct ANASTASIS_PolicyLookupOperation
+{
+
+  /**
+   * The url for this request, including parameters.
+   */
+  char *url;
+
+  /**
+   * Handle for the request.
+   */
+  struct GNUNET_CURL_Job *job;
+
+  /**
+   * Function to call with the result.
+   */
+  ANASTASIS_PolicyLookupCallback cb;
+
+  /**
+   * Closure for @a cb.
+   */
+  void *cb_cls;
+
+  /**
+   * Reference to the execution context.
+   */
+  struct GNUNET_CURL_Context *ctx;
+};
+
+
+/**
+ * Cancel a pending /policy GET request
+ *
+ * @param handle from the operation to cancel
+ */
+void
+ANASTASIS_policy_lookup_cancel (struct
+                                ANASTASIS_PolicyLookupOperation *plo)
+{
+  if (NULL != plo->job)
+  {
+    GNUNET_CURL_job_cancel (plo->job);
+    plo->job = NULL;
+  }
+  GNUNET_free (plo->url);
+  GNUNET_free (plo);
+}
+
+
+/**
+ * Process GET /policy response
+ */
+static void
+handle_policy_lookup_finished (void *cls,
+                               long response_code,
+                               const void *response)
+{
+  struct ANASTASIS_PolicyLookupOperation *plo = cls;
+  char *error;
+  enum ANASTASIS_ErrorCode code;
+  const json_t *json = response;
+
+  plo->job = NULL;
+  switch (response_code)
+  {
+  case 0:
+    /* Hard error */
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Backend didn't even return from GET /policy\n");
+    return;
+
+  case MHD_HTTP_OK:
+  case MHD_HTTP_NOT_FOUND:
+    plo->cb (plo->cb_cls,
+             response_code,
+             ANASTASIS_EC_NONE,
+             json);
+    break;
+  default:
+    /**
+     * The backend gave response, but it's error, log it.
+     * NOTE that json must be a ANASTASIS-specific error object (FIXME,
+     * need a link to error objects at docs)
+     */
+    if (-1 == json_unpack ((json_t *) json,
+                           "{s:s, s:I, s:s}",
+                           "error", &error,
+                           "code", &code))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                  "Failed GET /policy, error: %s, code: %d\n",
+                  error,
+                  code);
+      break;
+    }
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Failed /policy lookup, backend did not give"
+                " a valid error object, HTTP code was %lu\n",
+                response_code);
+  }
+
+  ANASTASIS_policy_lookup_cancel (plo);
+}
+
+
+/**
+ * Does a GET /policy.
+ *
+ * @param ctx execution context
+ * @param backend_url base URL of the merchant backend
+ * @param anastasis_pub public key of the user's account
+ * @param cb callback which will work the response gotten from the backend
+ * @param cb_cls closure to pass to the callback
+ * @return handle for this operation, NULL upon errors
+ */
+struct ANASTASIS_PolicyLookupOperation *
+ANASTASIS_policy_lookup (struct GNUNET_CURL_Context *ctx,
+                         const char *backend_url,
+                         const struct ANASTASIS_AccountPubP *anastasis_pub,
+                         ANASTASIS_PolicyLookupCallback cb,
+                         void *cb_cls)
+{
+  struct ANASTASIS_PolicyLookupOperation *plo;
+  CURL *eh;
+  char *acc_pub_str;
+  char *path;
+
+  plo = GNUNET_new (struct ANASTASIS_PolicyLookupOperation);
+  plo->ctx = ctx;
+  plo->cb = cb;
+  plo->cb_cls = cb_cls;
+  acc_pub_str = GNUNET_CRYPTO_eddsa_public_key_to_string (&anastasis_pub->pub);
+  GNUNET_asprintf (&path,
+                   "policy/%s",
+                   acc_pub_str);
+  GNUNET_free (acc_pub_str);
+  plo->url = TALER_url_join (backend_url,
+                             path,
+                             NULL);
+  GNUNET_free (path);
+  eh = curl_easy_init ();
+  if (CURLE_OK != curl_easy_setopt (eh,
+                                    CURLOPT_URL,
+                                    plo->url))
+  {
+    GNUNET_break (0);
+    return NULL;
+  }
+
+  if (NULL == (plo->job = GNUNET_CURL_job_add (ctx,
+                                               eh,
+                                               GNUNET_NO,
+                                               handle_policy_lookup_finished,
+                                               plo)))
+  {
+    GNUNET_break (0);
+    return NULL;
+
+  }
+
+  return plo;
+}
+
+
+/**
+ * Does a GET /policy for a specific version.
+ *
+ * @param ctx execution context
+ * @param backend_url base URL of the merchant backend
+ * @param anastasis_pub public key of the user's account
+ * @param cb callback which will work the response gotten from the backend
+ * @param cb_cls closure to pass to the callback
+ * @param version version of the policy to be requested
+ * @return handle for this operation, NULL upon errors
+ */
+struct ANASTASIS_PolicyLookupOperation *
+ANASTASIS_policy_lookup_version (struct GNUNET_CURL_Context *ctx,
+                                 const char *backend_url,
+                                 const struct
+                                 ANASTASIS_AccountPubP *anastasis_pub,
+                                 ANASTASIS_PolicyLookupCallback cb,
+                                 void *cb_cls,
+                                 uint32_t *version)
+{
+  struct ANASTASIS_PolicyLookupOperation *plo;
+  CURL *eh;
+  char *acc_pub_str;
+  char *path;
+
+  plo = GNUNET_new (struct ANASTASIS_PolicyLookupOperation);
+  plo->ctx = ctx;
+  plo->cb = cb;
+  plo->cb_cls = cb_cls;
+  acc_pub_str = GNUNET_CRYPTO_eddsa_public_key_to_string (&anastasis_pub->pub);
+  GNUNET_asprintf (&path,
+                   "policy/%s",
+                   acc_pub_str);
+  GNUNET_free (acc_pub_str);
+  plo->url = TALER_url_join (backend_url,
+                             path,
+                             "version",
+                             version,
+                             NULL);
+  GNUNET_free (path);
+  eh = curl_easy_init ();
+  if (CURLE_OK != curl_easy_setopt (eh,
+                                    CURLOPT_URL,
+                                    plo->url))
+  {
+    GNUNET_break (0);
+    return NULL;
+  }
+
+  if (NULL == (plo->job = GNUNET_CURL_job_add (ctx,
+                                               eh,
+                                               GNUNET_NO,
+                                               handle_policy_lookup_finished,
+                                               plo)))
+  {
+    GNUNET_break (0);
+    return NULL;
+
+  }
+
+  return plo;
+}
diff --git a/src/lib/anastasis_api_policy_store.c 
b/src/lib/anastasis_api_policy_store.c
new file mode 100644
index 0000000..4e5130d
--- /dev/null
+++ b/src/lib/anastasis_api_policy_store.c
@@ -0,0 +1,424 @@
+/*
+  This file is part of ANASTASIS
+  Copyright (C) 2014-2019 GNUnet e.V. and INRIA
+
+  ANASTASIS is free software; you can redistribute it and/or modify
+  it under the terms of the GNU Lesser General Public License as
+  published by the Free Software Foundation; either version 2.1,
+  or (at your option) any later version.
+
+  ANASTASIS is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with ANASTASIS; see the file COPYING.LGPL.  If not,
+  see <http://www.gnu.org/licenses/>
+*/
+
+/**
+ * @file lib/anastasis_api_policy_store.c
+ * @brief Implementation of the /policy GET and POST
+ * @author Christian Grothoff
+ * @author Dennis Neufeld
+ * @author Dominik Meister
+ */
+#include "platform.h"
+#include <curl/curl.h>
+#include <jansson.h>
+#include <microhttpd.h> /* just for HTTP status codes */
+#include <gnunet/gnunet_util_lib.h>
+#include <gnunet/gnunet_curl_lib.h>
+#include <taler/taler_signatures.h>
+#include <taler/taler_json_lib.h>
+#include <taler/taler_curl_lib.h>
+#include <taler/taler_util.h>
+#include "anastasis_service.h"
+
+
+struct ANASTASIS_PolicyStoreOperation
+{
+  /**
+   * Complete URL where the backend offers /policy
+   */
+  char *url;
+
+  /**
+   * Handle for the request.
+   */
+  struct GNUNET_CURL_Job *job;
+
+  /**
+   * The CURL context to connect to the backend
+   */
+  struct GNUNET_CURL_Context *ctx;
+
+  /**
+   * The callback to pass the backend response to
+   */
+  ANASTASIS_PolicyStoreCallback cb;
+
+  /**
+   * Closure for @e cb.
+   */
+  void *cb_cls;
+
+  /**
+   * Payment URI we received from the service, or NULL.
+   */
+  char *pay_uri;
+
+  /**
+   * Hash of the data we are uploading.
+   */
+  struct GNUNET_HashCode new_recovery_data_hash;
+};
+
+
+/**
+ * Callback to process POST /policy response
+ *
+ * @param cls the `struct ANASTASIS_PolicyStoreOperation`
+ * @param response_code HTTP response code, 0 on error
+ * @param data
+ * @param data_size
+ */
+static void
+handle_policy_store_finished (void *cls,
+                              long response_code,
+                              const void *data,
+                              size_t data_size)
+{
+  struct ANASTASIS_PolicyStoreOperation *pso = cls;
+  enum TALER_ErrorCode ec = TALER_EC_INVALID;
+  struct ANASTASIS_UploadDetails ud;
+  struct ANASTASIS_UploadDetails *udp;
+
+  pso->job = NULL;
+  udp = NULL;
+  memset (&ud, 0, sizeof (ud));
+  switch (response_code)
+  {
+  case 0:
+    break;
+  case MHD_HTTP_NO_CONTENT:
+    ud.us = ANASTASIS_US_SUCCESS;
+    ud.details.curr_backup_hash = &pso->new_recovery_data_hash;
+    udp = &ud;
+    ec = TALER_EC_NONE;
+    break;
+  case MHD_HTTP_NOT_MODIFIED:
+    ud.us = ANASTASIS_US_SUCCESS;
+    ud.details.curr_backup_hash = &pso->new_recovery_data_hash;
+    udp = &ud;
+    ec = TALER_EC_NONE;
+    break;
+  case MHD_HTTP_BAD_REQUEST:
+    GNUNET_break (0);
+    ec = TALER_JSON_get_error_code2 (data,
+                                     data_size);
+    break;
+  case MHD_HTTP_PAYMENT_REQUIRED:
+    ud.us = ANASTASIS_US_PAYMENT_REQUIRED;
+    ud.details.payment_request = pso->pay_uri;
+    udp = &ud;
+    ec = TALER_EC_NONE;
+    break;
+  case MHD_HTTP_FORBIDDEN:
+    GNUNET_break (0);
+    ec = TALER_JSON_get_error_code2 (data,
+                                     data_size);
+    break;
+  case MHD_HTTP_CONFLICT:
+    ud.us = ANASTASIS_US_CONFLICTING_BACKUP;
+    GNUNET_CRYPTO_hash (data,
+                        data_size,
+                        &ud.details.recovered_backup.existing_backup_hash);
+    ud.details.recovered_backup.existing_backup_size
+      = data_size;
+    ud.details.recovered_backup.existing_backup
+      = data;
+    udp = &ud;
+    ec = TALER_EC_NONE;
+    break;
+  case MHD_HTTP_GONE:
+    ec = TALER_JSON_get_error_code2 (data,
+                                     data_size);
+    break;
+  case MHD_HTTP_LENGTH_REQUIRED:
+    GNUNET_break (0);
+    break;
+  case MHD_HTTP_REQUEST_ENTITY_TOO_LARGE:
+    ec = TALER_JSON_get_error_code2 (data,
+                                     data_size);
+    break;
+  case MHD_HTTP_TOO_MANY_REQUESTS:
+    ec = TALER_JSON_get_error_code2 (data,
+                                     data_size);
+    break;
+  }
+  if (NULL != pso->cb)
+  {
+    pso->cb (pso->cb_cls,
+             ec,
+             response_code,
+             udp);
+    pso->cb = NULL;
+  }
+  ANASTASIS_policy_store_cancel (pso);
+}
+
+
+/**
+ * Cancel a POST /policy request.
+ *
+ * @param pso the policy store operation to cancel
+ */
+void
+ANASTASIS_policy_store_cancel (struct
+                               ANASTASIS_PolicyStoreOperation *pso)
+{
+  if (NULL != pso->job)
+  {
+    GNUNET_CURL_job_cancel (pso->job);
+    pso->job = NULL;
+  }
+  GNUNET_free (pso->pay_uri);
+  GNUNET_free (pso->url);
+  GNUNET_free (pso);
+}
+
+
+/**
+ * Handle HTTP header received by curl.
+ *
+ * @param buffer one line of HTTP header data
+ * @param size size of an item
+ * @param nitems number of items passed
+ * @param userdata our `struct ANASTASIS_StorePolicyOperation *`
+ * @return `size * nitems`
+ */
+static size_t
+handle_header (char *buffer,
+               size_t size,
+               size_t nitems,
+               void *userdata)
+{
+  struct ANASTASIS_PolicyStoreOperation *pso = userdata;
+  size_t total = size * nitems;
+  char *ndup;
+  const char *hdr_type;
+  char *hdr_val;
+
+  ndup = GNUNET_strndup (buffer,
+                         total);
+  hdr_type = strtok (ndup,
+                     ":");
+  if (NULL == hdr_type)
+  {
+    GNUNET_free (ndup);
+    return total;
+  }
+  hdr_val = strtok (NULL,
+                    "");
+  if (NULL == hdr_val)
+  {
+    GNUNET_free (ndup);
+    return total;
+  }
+  if (' ' == *hdr_val)
+    hdr_val++;
+  if (0 == strcasecmp (hdr_type,
+                       "Taler"))
+  {
+    /* found payment URI we care about! */
+    pso->pay_uri = GNUNET_strdup (hdr_val);
+  }
+  GNUNET_free (ndup);
+  return total;
+}
+
+
+
+/**
+ * Store policies, does a POST /policy/$AccountPub
+ *
+ * @param ctx the CURL context used to connect to the backend
+ * @param backend_url backend's base URL, including final "/"
+ * @param anastasis_pub public key of the user's account
+ * @param anastasis_priv private key of the user's account
+ * @param prev_recovery_data_hash hash of the privious policy update, NULL for 
the first upload ever
+ * @param recovery_data policy data to be stored
+ * @param recovery_data_size number of bytes in @a recovery_data
+ * @param payment_requested #GNUNET_YES if the client wants to pay more for 
the account now
+ * @param paymentSecretP payment identifier of last payment
+ * @param cb callback processing the response from /policy
+ * @param cb_cls closure for cb
+ * @return handle for the operation
+ */
+struct ANASTASIS_PolicyStoreOperation *
+ANASTASIS_policy_store (struct GNUNET_CURL_Context *ctx,
+                        const char *backend_url,
+                        const struct
+                        ANASTASIS_AccountPrivP *anastasis_priv,
+                        const struct 
+                        GNUNET_HashCode *prev_recovery_data_hash,
+                        const void *recovery_data,
+                        size_t recovery_data_size,
+                        int payment_requested,
+                        const struct
+                        ANASTASIS_PaymentSecretP *paymentSecretP,
+                        ANASTASIS_PolicyStoreCallback cb,
+                        void *cb_cls)
+{
+  struct ANASTASIS_PolicyStoreOperation *pso;
+  struct ANASTASIS_AccountSignatureP account_sig;
+  struct ANASTASIS_UploadSignaturePS usp;
+  CURL *eh;
+  struct curl_slist *job_headers;
+
+  memset (&usp, 0, sizeof (usp));
+  usp.purpose.purpose = htonl (TALER_SIGNATURE_ANASTASIS_POLICY_UPLOAD);
+  usp.purpose.size = htonl (sizeof (usp));
+  if (NULL != prev_recovery_data_hash)
+    usp.old_recovery_data_hash = *prev_recovery_data_hash;
+  GNUNET_CRYPTO_hash (recovery_data,
+                      recovery_data_size,
+                      &usp.new_recovery_data_hash);
+  if (GNUNET_OK !=
+      GNUNET_CRYPTO_eddsa_sign (&anastasis_priv->priv,
+                                &usp.purpose,
+                                &account_sig.eddsa_sig))
+  {
+    GNUNET_break (0);
+    return NULL;
+  }
+
+  /* setup our HTTP headers */
+  job_headers = NULL;
+  {
+    struct curl_slist *ext;
+    char *val;
+    char *hdr;
+
+    /* Set Sync-Signature header */
+    val = GNUNET_STRINGS_data_to_string_alloc (&account_sig,
+                                               sizeof (account_sig));
+    GNUNET_asprintf (&hdr,
+                     "Anastasis-Policy-Signature: %s",
+                     val);
+    GNUNET_free (val);
+    ext = curl_slist_append (job_headers,
+                             hdr);
+    GNUNET_free (hdr);
+    if (NULL == ext)
+    {
+      GNUNET_break (0);
+      curl_slist_free_all (job_headers);
+      return NULL;
+    }
+    job_headers = ext;
+
+    /* set Etag header */
+    val = GNUNET_STRINGS_data_to_string_alloc (&usp.new_recovery_data_hash,
+                                               sizeof (struct 
GNUNET_HashCode));
+    GNUNET_asprintf (&hdr,
+                     "Etag: %s",
+                     val);
+    GNUNET_free (val);
+    ext = curl_slist_append (job_headers,
+                             hdr);
+    GNUNET_free (hdr);
+    if (NULL == ext)
+    {
+      GNUNET_break (0);
+      curl_slist_free_all (job_headers);
+      return NULL;
+    }
+    job_headers = ext;
+
+    /* Setup If-Match header */
+    if (NULL != prev_recovery_data_hash)
+    {
+      val = GNUNET_STRINGS_data_to_string_alloc (&usp.old_recovery_data_hash,
+                                                 sizeof (struct
+                                                         GNUNET_HashCode));
+      GNUNET_asprintf (&hdr,
+                       "If-Match: %s",
+                       val);
+      GNUNET_free (val);
+      ext = curl_slist_append (job_headers,
+                               hdr);
+      GNUNET_free (hdr);
+      if (NULL == ext)
+      {
+        GNUNET_break (0);
+        curl_slist_free_all (job_headers);
+        return NULL;
+      }
+      job_headers = ext;
+    }
+  }
+  /* Finished setting up headers */
+
+  pso = GNUNET_new (struct ANASTASIS_PolicyStoreOperation);
+  pso->new_recovery_data_hash = usp.new_recovery_data_hash;
+  {
+    char *acc_pub_str;
+    char *path;
+    struct ANASTASIS_AccountPubP pub;
+
+    GNUNET_CRYPTO_eddsa_key_get_public (&anastasis_priv->priv,
+                                        &pub.pub);
+    
+    acc_pub_str = GNUNET_CRYPTO_eddsa_public_key_to_string (&pub.pub);
+    GNUNET_asprintf (&path,
+                    "policy/%s",
+                    acc_pub_str);
+    GNUNET_free (acc_pub_str);
+    pso->url = TALER_url_join (backend_url,
+                              "policy",
+                              pub);
+    GNUNET_free (path);
+  }
+  pso->ctx = ctx;
+  pso->cb = cb;
+  pso->cb_cls = cb_cls;
+  eh = curl_easy_init ();
+  GNUNET_assert (CURLE_OK ==
+                 curl_easy_setopt (eh,
+                                   CURLOPT_URL,
+                                   pso->url));
+  GNUNET_assert (CURLE_OK ==
+                 curl_easy_setopt (eh,
+                                   CURLOPT_FOLLOWLOCATION,
+                                   1L));
+  GNUNET_assert (CURLE_OK ==
+                 curl_easy_setopt (eh,
+                                   CURLOPT_TCP_FASTOPEN,
+                                   1L));
+  GNUNET_assert (CURLE_OK ==
+                 curl_easy_setopt (eh,
+                                   CURLOPT_POSTFIELDS,
+                                   recovery_data));
+  GNUNET_assert (CURLE_OK ==
+                 curl_easy_setopt (eh,
+                                   CURLOPT_POSTFIELDSIZE,
+                                   (long) recovery_data_size));
+  GNUNET_assert (CURLE_OK ==
+                 curl_easy_setopt (eh,
+                                   CURLOPT_HEADERFUNCTION,
+                                   &handle_header));
+  GNUNET_assert (CURLE_OK ==
+                 curl_easy_setopt (eh,
+                                   CURLOPT_HEADERDATA,
+                                   pso));
+  pso->job = GNUNET_CURL_job_add_raw (ctx,
+                                      eh,
+                                      job_headers,
+                                      &handle_policy_store_finished,
+                                      pso);
+  curl_slist_free_all (job_headers);
+  return pso;
+}
diff --git a/src/lib/test_anastasis_api.c b/src/lib/test_anastasis_api.c
index 82cefec..c1876fb 100644
--- a/src/lib/test_anastasis_api.c
+++ b/src/lib/test_anastasis_api.c
@@ -1,6 +1,6 @@
 /*
   This file is part of TALER
-  Copyright (C) 2014-2018 Taler Systems SA
+  Copyright (C) 2014-2019 Taler Systems SA
 
   TALER is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as
@@ -18,13 +18,12 @@
 */
 
 /**
- * @file exchange/test_merchant_api_new.c
- * @brief testcase to test exchange's HTTP API interface
- * @author Sree Harsha Totakura <address@hidden>
+ * @file lib/test_anastasis_api.c
+ * @brief testcase to test anastasis' HTTP API interface
  * @author Christian Grothoff
- * @author Marcello Stanisci
+ * @author Dennis Neufeld
+ * @author Dominik Meister
  */
-
 #include "platform.h"
 #include <taler/taler_util.h>
 #include <taler/taler_signatures.h>
@@ -51,6 +50,26 @@
 
 static const char *pickup_amounts_1[] = {"EUR:5", NULL};
 
+/**
+ * User private key, set to a random value
+ */
+static struct ANASTASIS_AccountPrivP accountPriv;
+
+/**
+ * User public key
+ */
+static struct ANASTASIS_AccountPubP accountPub;
+
+/**
+ * Payment Secret for the test, set to a random value
+ */
+static struct ANASTASIS_PaymentSecretP paymentSecret;
+
+/**
+ * Recoverydata which should be stored, set to a random value
+ */
+static void *recoveryData;
+
 /**
  * URL of the fakebank.
  */
@@ -221,6 +240,19 @@ static void
 run (void *cls,
      struct TALER_TESTING_Interpreter *is)
 {
+  
+  //fill data
+  const char *str = "AHV123456789";
+  GNUNET_CRYPTO_eddsa_private_key_from_string (str,
+                                               sizeof (str),
+                                               &accountPriv.priv);
+  GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
+                              &recoveryData,
+                              sizeof (recoveryData));
+  GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
+                              &paymentSecret,
+                              sizeof (paymentSecret));
+
   struct TALER_TESTING_Command pay[] = {
     /**
      * Move money to the exchange's bank account.
@@ -245,7 +277,6 @@ run (void *cls,
       "create-reserve-1",
       "EUR:5",
       MHD_HTTP_OK),
-
     TALER_TESTING_cmd_withdraw_amount
       ("withdraw-coin-2",
       "create-reserve-1",
@@ -265,6 +296,13 @@ run (void *cls,
 
   struct TALER_TESTING_Command policy[] = {
     // FIXME: Code for policy handling
+    ANASTASIS_TESTING_cmd_policy_store ("policy-store-1",
+                                        anastasis_url,
+                                        MHD_HTTP_OK,
+                                        &accountPriv,
+                                        &paymentSecret,
+                                        recoveryData,
+                                        sizeof (recoveryData)),
 
     TALER_TESTING_cmd_end ()
   };
@@ -284,12 +322,12 @@ run (void *cls,
                              policy),
 
     TALER_TESTING_cmd_batch ("truth",
-                               truth),
+                             truth),
 
     /**
-    * End the suite.  Fixme: better to have a label for this
-    * too, as it shows a "(null)" token on logs.
-    */
+     * End the suite.  Fixme: better to have a label for this
+     * too, as it shows a "(null)" token on logs.
+     */
     TALER_TESTING_cmd_end ()
   };
 
@@ -307,7 +345,7 @@ main (int argc,
   unsetenv ("XDG_DATA_HOME");
   unsetenv ("XDG_CONFIG_HOME");
 
-  GNUNET_log_setup ("test-anastasis-api-new",
+  GNUNET_log_setup ("test-anastasis-api",
                     "DEBUG",
                     NULL);
   if (NULL ==
@@ -368,4 +406,4 @@ main (int argc,
   return 0;
 }
 
-/* end of test_merchant_api_new.c */
+/* end of test_merchant_api.c */
diff --git a/src/lib/testing_api_cmd_policy_lookup.c 
b/src/lib/testing_api_cmd_policy_lookup.c
new file mode 100644
index 0000000..8cb45a3
--- /dev/null
+++ b/src/lib/testing_api_cmd_policy_lookup.c
@@ -0,0 +1,63 @@
+/*
+  This file is part of ANASTASIS
+  Copyright (C) 2014-2019 Taler Systems SA
+
+  ANASTASIS is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as
+  published by the Free Software Foundation; either version 3, or
+  (at your option) any later version.
+
+  ANASTASIS is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public
+  License along with ANASTASIS; see the file COPYING.  If not, see
+  <http://www.gnu.org/licenses/>
+*/
+
+/**
+ * @file lib/testing_api_cmd_policy_lookup.c
+ * @brief command to execute the anastasis backend service.
+ * @author Dennis Neufeld
+ * @author Dominik Meister
+ */
+
+#include "platform.h"
+#include "anastasis_service.h"
+#include "anastasis_testing_lib.h"
+#include <taler/taler_util.h>
+#include <taler/taler_testing_lib.h>
+
+
+/**
+ * State for a "policy lookup" CMD.
+ */
+struct PolicyLookupState
+{
+  /**
+   * The interpreter state.
+   */
+  struct TALER_TESTING_Interpreter *is;
+
+  /**
+   * Eddsa Publickey.
+   */
+  const struct ANASTASIS_AccountPubP anastasis_pub;
+
+  /**
+   * URL of the anastasis backend.
+   */
+  const char *anastasis_url;
+
+  /**
+   * Expected status code.
+   */
+  unsigned int http_status;
+
+  /**
+   * The  /policy GET operation handle.
+   */
+  struct ANASTASIS_PolicyLookupOperation *plo;
+};
diff --git a/src/lib/testing_api_cmd_policy_store.c 
b/src/lib/testing_api_cmd_policy_store.c
new file mode 100644
index 0000000..e04337f
--- /dev/null
+++ b/src/lib/testing_api_cmd_policy_store.c
@@ -0,0 +1,247 @@
+/*
+  This file is part of ANASTASIS
+  Copyright (C) 2014-2019 Taler Systems SA
+
+  ANASTASIS is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as
+  published by the Free Software Foundation; either version 3, or
+  (at your option) any later version.
+
+  ANASTASIS is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public
+  License along with ANASTASIS; see the file COPYING.  If not, see
+  <http://www.gnu.org/licenses/>
+*/
+
+/**
+ * @file lib/testing_api_cmd_policy_store.c
+ * @brief command to execute the anastasis backend service.
+ * @author Marcello Stanisci
+ */
+
+#include "platform.h"
+#include "anastasis_service.h"
+#include "anastasis_testing_lib.h"
+#include <taler/taler_util.h>
+#include <taler/taler_testing_lib.h>
+
+/**
+ * State for a "policy store" CMD.
+ */
+struct PolicyStoreState
+{
+
+  /**
+   * The policy data.
+   */
+  const void *recovery_data;
+
+  /** 
+   * Number of bytes in @e recovery_data
+   */
+  size_t recovery_data_size;
+
+  /**
+   * Expected status code.
+   */
+  unsigned int http_status;
+
+  /**
+   * Eddsa Publickey.
+   */
+  const struct ANASTASIS_AccountPubP *anastasis_pub;
+
+  /**
+   * Eddsa Privatekey.
+   */
+  const struct ANASTASIS_AccountPrivP *anastasis_priv;
+
+  /**
+   * The /policy POST operation handle.
+   */
+  struct ANASTASIS_PolicyStoreOperation *pso;
+
+  /**
+   * The nonce.
+   */
+  struct GNUNET_CRYPTO_EddsaPublicKey nonce;
+
+  /**
+   * URL of the anastasis backend.
+   */
+  const char *anastasis_url;
+
+  /**
+   * The interpreter state.
+   */
+  struct TALER_TESTING_Interpreter *is;
+
+  /**
+   * Payment identifier.
+   */
+  const struct ANASTASIS_PaymentSecretP *payment_id;
+};
+
+
+/**
+ * State for a "policy lookup" CMD.
+ */
+struct PolicyLookupState
+{
+  /**
+   * The interpreter state.
+   */
+  struct TALER_TESTING_Interpreter *is;
+
+  /**
+   * Eddsa Publickey.
+   */
+  const struct ANASTASIS_AccountPubP anastasis_pub;
+
+  /**
+   * URL of the anastasis backend.
+   */
+  const char *anastasis_url;
+
+  /**
+   * Expected status code.
+   */
+  unsigned int http_status;
+
+  /**
+   * The  /policy GET operation handle.
+   */
+  struct ANASTASIS_PolicyLookupOperation *plo;
+};
+
+
+/**
+ * Function called with the results of a #policy_store().
+ *
+ * @param cls closure
+ * @param ec Taler error code
+ * @param http_status HTTP status of the request
+ * @param ud details about the upload operation
+ */
+static void
+policy_store_cb (void *cls,
+                 enum ANASTASIS_ErrorCode ec,
+                 unsigned int http_status,
+                 const struct ANASTASIS_UploadDetails *ud)
+{
+  struct PolicyStoreState *pss = cls;
+
+  // FIXME: next!
+}
+
+
+/**
+ * Run a "policy store" CMD.
+ *
+ * @param cls closure.
+ * @param cmd command currently being run.
+ * @param is interpreter state.
+ */
+static void
+policy_store_run (void *cls,
+                  const struct TALER_TESTING_Command *cmd,
+                  struct TALER_TESTING_Interpreter *is)
+{
+  struct PolicyStoreState *pss = cls;
+
+  pss->is = is;
+
+  GNUNET_CRYPTO_random_block
+    (GNUNET_CRYPTO_QUALITY_WEAK,
+    &pss->nonce,
+    sizeof (struct GNUNET_CRYPTO_EddsaPublicKey));
+
+  pss->pso = ANASTASIS_policy_store (is->ctx,
+                                     pss->anastasis_url,
+                                     pss->anastasis_priv,
+                                     NULL /* pre_recovery_data_hash */,
+                                     pss->recovery_data,
+                                     pss->recovery_data_size,
+                                     GNUNET_NO /* payment req */,
+                                     pss->payment_id,
+                                     &policy_store_cb,
+                                     pss);
+  GNUNET_assert (NULL != pss->pso);
+}
+
+
+/**
+ * Free the state of a "policy sore" CMD, and possibly
+ * cancel it if it did not complete.
+ *
+ * @param cls closure.
+ * @param cmd command being freed.
+ */
+static void
+policy_store_cleanup (void *cls,
+                      const struct TALER_TESTING_Command *cmd)
+{
+  struct PolicyStoreState *pss = cls;
+
+  if (NULL != pss->pso)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                "Command '%s' did not complete (policy post)\n",
+                cmd->label);
+    ANASTASIS_policy_store_cancel (pss->pso);
+    pss->pso = NULL;
+  }
+
+  // GNUNET_free_non_null ((void *) pss->order_id);
+  GNUNET_free (pss);
+}
+
+
+/**
+ * Make the "policy store" command.
+ *
+ * @param label command label
+ * @param anastasis_url base URL of the anastasis serving
+ *        the policy store request.
+ * @param http_status expected HTTP status.
+ * @param priv private account identifier
+ * @param pub account identifier
+ * @param payment_id payment identifier
+ * @param recovery_data recovery data to post
+ * @param recovery_data_size size of recovery/policy data
+ * @return the command
+ */
+struct TALER_TESTING_Command
+ANASTASIS_TESTING_cmd_policy_store (const char *label,
+                                    const char *anastasis_url,
+                                    unsigned int http_status,
+                                    const struct
+                                    ANASTASIS_AccountPrivP *priv,
+                                    const struct
+                                    ANASTASIS_PaymentSecretP *payment_id,
+                                    const void *recovery_data,
+                                    size_t recovery_data_size)
+{
+  struct PolicyStoreState *pss;
+
+  pss = GNUNET_new (struct PolicyStoreState);
+  pss->anastasis_priv = priv;
+  pss->recovery_data = recovery_data;
+  pss->recovery_data_size = recovery_data_size;
+  pss->payment_id = payment_id;
+  pss->http_status = http_status;
+  pss->anastasis_url = anastasis_url;
+
+  struct TALER_TESTING_Command cmd = {
+    .cls = pss,
+    .label = label,
+    .run = &policy_store_run,
+    .cleanup = &policy_store_cleanup
+  };
+
+  return cmd;
+}
\ No newline at end of file
diff --git a/src/util/Makefile.am b/src/util/Makefile.am
index 4736d81..677ad84 100644
--- a/src/util/Makefile.am
+++ b/src/util/Makefile.am
@@ -24,6 +24,4 @@ libanastasisutil_la_LIBADD = \
   $(XLIB)
 libanastasisutil_la_LDFLAGS = \
   -version-info 0:0:0 \
-  -export-dynamic -no-undefined
-
-
+  -export-dynamic -no-undefined
\ No newline at end of file

-- 
To stop receiving notification emails like this one, please contact
address@hidden.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]