[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[taler-challenger] branch master updated: -more basic work on challenger
From: |
gnunet |
Subject: |
[taler-challenger] branch master updated: -more basic work on challenger |
Date: |
Sat, 06 May 2023 15:33:38 +0200 |
This is an automated email from the git hooks/post-receive script.
grothoff pushed a commit to branch master
in repository challenger.
The following commit(s) were added to refs/heads/master by this push:
new f3550bf -more basic work on challenger
f3550bf is described below
commit f3550bf44f67735195a09c1a18500300d7a252d8
Author: Christian Grothoff <christian@grothoff.org>
AuthorDate: Sat May 6 15:33:33 2023 +0200
-more basic work on challenger
---
contrib/enter-address-form.must | 23 ++
contrib/enter-tan-form.must | 29 ++
src/challenger/challenger-httpd.c | 51 +++
src/challenger/challenger-httpd.h | 16 +
src/challenger/challenger-httpd_auth.c | 297 ++++++++++++++-
src/challenger/challenger-httpd_challenge.c | 399 ++++++++++++++++++---
src/challenger/challenger-httpd_challenge.h | 7 +
src/challenger/challenger-httpd_common.c | 33 ++
src/challenger/challenger-httpd_common.h | 32 ++
src/challenger/challenger-httpd_info.c | 91 ++++-
src/challenger/challenger-httpd_login.c | 5 +-
src/challenger/challenger-httpd_solve.c | 279 +++++++++++++-
src/challengerdb/challenger-0001.sql | 9 +-
.../pg_challenge_set_address_and_pin.c | 94 ++---
.../pg_challenge_set_address_and_pin.h | 12 +-
src/include/challenger_database_plugin.h | 60 +++-
16 files changed, 1296 insertions(+), 141 deletions(-)
diff --git a/contrib/enter-address-form.must b/contrib/enter-address-form.must
new file mode 100644
index 0000000..62a5f89
--- /dev/null
+++ b/contrib/enter-address-form.must
@@ -0,0 +1,23 @@
+<html>
+<head>
+<title>Enter your address</title>
+</head>
+<body>
+<form action="/challenge/{{nonce}}" method="POST">
+ <div>
+ <label for="say">What is your address?</label>
+ <input
+ name="address"
+ id="address"
+ maxlength="512"
+ value="{{last_address}}"
+ {{#fixed_address}}readonly{{/fixed_address}}
+ />
+ </div>
+ (You can change address another {{changes_left}} times.)
+ <div>
+ <button>Submit</button>
+ </div>
+</form>
+</body>
+</html>
\ No newline at end of file
diff --git a/contrib/enter-tan-form.must b/contrib/enter-tan-form.must
new file mode 100644
index 0000000..e40aa10
--- /dev/null
+++ b/contrib/enter-tan-form.must
@@ -0,0 +1,29 @@
+<html>
+<head>
+<title>Enter your TAN</title>
+</head>
+<body>
+ {{#transmitted}}
+ A TAN was sent to your address "{{address}}".
+ {{transmitted}}
+ {{^transmitted}}
+ We recently already sent a TAN to your address "{{address}}".
+ A new TAN will not be transmitted again before {{next_tx_time}}.
+ {{/transmitted}}
+
+ <form action="/solve/{{nonce}}" method="POST">
+ <div>
+ <label for="say">Please enter the TAN your received to
authenticate.</label>
+ <input
+ name="pin"
+ id="pin"
+ maxlength="64"
+ />
+ </div>
+ (You have {{attempts_left}} attempts left.)
+ <div>
+ <button>Submit</button>
+ </div>
+</form>
+</body>
+</html>
diff --git a/src/challenger/challenger-httpd.c
b/src/challenger/challenger-httpd.c
index b147e39..14fae3e 100644
--- a/src/challenger/challenger-httpd.c
+++ b/src/challenger/challenger-httpd.c
@@ -80,11 +80,28 @@ struct CHALLENGER_DatabasePlugin *db;
*/
struct GNUNET_TIME_Relative CH_validation_duration;
+/**
+ * How long validated data considered to be valid?
+ */
+struct GNUNET_TIME_Relative CH_validation_expiration;
+
/**
* How often do we retransmit the challenge.
*/
struct GNUNET_TIME_Relative CH_pin_retransmission_frequency;
+/**
+ * Type of addresses this challenger validates.
+ */
+char *CH_address_type;
+
+/**
+ * Helper command to run for transmission of
+ * challenge values.
+ */
+char *CH_auth_command;
+
+
/**
* A client has requested the given url using the given method
* (#MHD_HTTP_METHOD_GET, #MHD_HTTP_METHOD_PUT,
@@ -293,6 +310,7 @@ static void
do_shutdown (void *cls)
{
(void) cls;
+ CH_wakeup_challenge_on_shutdown ();
if (NULL != mhd_task)
{
GNUNET_SCHEDULER_cancel (mhd_task);
@@ -511,6 +529,39 @@ run (void *cls,
"VALIDATION_DURATION");
return;
}
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_time (config,
+ "CHALLENGER",
+ "VALIDATION_EXPIRATION",
+ &CH_validation_expiration))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "CHALLENGER",
+ "VALIDATION_EXPIRATION");
+ return;
+ }
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_filename (config,
+ "CHALLENGER",
+ "AUTH_COMMAND",
+ &CH_auth_command))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "CHALLENGER",
+ "AUTH_COMMAND");
+ return;
+ }
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_filename (config,
+ "CHALLENGER",
+ "ADDRESS_TYPE",
+ &CH_address_type))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "CHALLENGER",
+ "ADDRESS_TYPE");
+ return;
+ }
TALER_MHD_setup (go);
result = EXIT_NOTCONFIGURED;
diff --git a/src/challenger/challenger-httpd.h
b/src/challenger/challenger-httpd.h
index d3e129a..478310e 100644
--- a/src/challenger/challenger-httpd.h
+++ b/src/challenger/challenger-httpd.h
@@ -129,11 +129,27 @@ extern struct CHALLENGER_DatabasePlugin *db;
*/
extern struct GNUNET_CURL_Context *CH_ctx;
+/**
+ * Helper command to run for transmission of
+ * challenge values.
+ */
+extern char *CH_auth_command;
+
+/**
+ * Type of addresses this challenger validates.
+ */
+extern char *CH_address_type;
+
/**
* How long is an individual validation request valid?
*/
extern struct GNUNET_TIME_Relative CH_validation_duration;
+/**
+ * How long validated data considered to be valid?
+ */
+extern struct GNUNET_TIME_Relative CH_validation_expiration;
+
/**
* How often do we retransmit the challenge.
*/
diff --git a/src/challenger/challenger-httpd_auth.c
b/src/challenger/challenger-httpd_auth.c
index fcc6463..22e7120 100644
--- a/src/challenger/challenger-httpd_auth.c
+++ b/src/challenger/challenger-httpd_auth.c
@@ -33,10 +33,40 @@
struct AuthContext
{
+ /**
+ * Nonce of the validation process the request is about.
+ */
+ struct CHALLENGER_ValidationNonceP nonce;
+
/**
* Handle for processing uploaded data.
*/
struct MHD_PostProcessor *pp;
+
+ /**
+ * Uploaded 'client_id' field from POST data.
+ */
+ char *client_id;
+
+ /**
+ * Uploaded 'client_id' field from POST data.
+ */
+ char *redirect_uri;
+
+ /**
+ * Uploaded 'client_secret' field from POST data.
+ */
+ char *client_secret;
+
+ /**
+ * Uploaded 'code' field from POST data.
+ */
+ char *code;
+
+ /**
+ * Uploaded 'grant_type' field from POST data.
+ */
+ char *grant_type;
};
@@ -55,6 +85,11 @@ cleanup_ctx (void *cls)
GNUNET_break_op (MHD_YES ==
MHD_destroy_post_processor (bc->pp));
}
+ GNUNET_free (bc->client_id);
+ GNUNET_free (bc->redirect_uri);
+ GNUNET_free (bc->client_secret);
+ GNUNET_free (bc->code);
+ GNUNET_free (bc->grant_type);
GNUNET_free (bc);
}
@@ -89,10 +124,58 @@ post_iter (void *cls,
size_t size)
{
struct AuthContext *bc = cls;
+ struct Map
+ {
+ const char *name;
+ char **ptr;
+ } map[] = {
+ {
+ .name = "client_id",
+ .ptr = &bc->client_id
+ },
+ {
+ .name = "redirect_uri",
+ .ptr = &bc->redirect_uri
+ },
+ {
+ .name = "client_secret",
+ .ptr = &bc->client_secret
+ },
+ {
+ .name = "code",
+ .ptr = &bc->code
+ },
+ {
+ .name = "grant_type",
+ .ptr = &bc->grant_type
+ },
+ {
+ .name = NULL,
+ .ptr = NULL
+ },
+ };
+ char **ptr = NULL;
+ size_t slen;
- (void) bc;
- GNUNET_break (0);
- return MHD_NO;
+ for (unsigned int i = 0; NULL != map[i].name; i++)
+ if (0 == strcmp (key,
+ map[i].name))
+ ptr = map[i].ptr;
+ if (NULL == ptr)
+ return MHD_YES; /* ignore */
+ if (NULL == *ptr)
+ slen = 0;
+ else
+ slen = strlen (*ptr);
+ if (NULL == *ptr)
+ *ptr = GNUNET_malloc (size + 1);
+ else
+ *ptr = GNUNET_realloc (*ptr,
+ slen + size + 1);
+ memcpy ((*ptr)[slen],
+ data,
+ size);
+ return MHD_YES;
}
@@ -102,6 +185,7 @@ CH_handler_auth (struct CH_HandlerContext *hc,
size_t *upload_data_size)
{
struct AuthContext *bc = hc->ctx;
+ char *access_token;
if (NULL == bc)
{
@@ -127,10 +211,211 @@ CH_handler_auth (struct CH_HandlerContext *hc,
*upload_data_size = 0;
if (MHD_YES == res)
return MHD_YES;
- /* FIXME: return more specific error if possible... */
return MHD_NO;
}
+ if ( (NULL == bc->grant_type) ||
+ (0 != strcmp (bc->grant_type,
+ "authorization_code")) )
+ {
+ GNUNET_break_op (0);
+ return TALER_MHD_reply_with_error (hc->connection,
+ MHD_HTTP_BAD_REQUEST,
+ TALER_EC_GENERIC_PARAMETER_INVALID,
+ "authorization_code");
+ }
+
+ if (NULL == bc->code)
+ {
+ GNUNET_break_op (0);
+ return TALER_MHD_reply_with_error (hc->connection,
+ MHD_HTTP_BAD_REQUEST,
+ TALER_EC_GENERIC_PARAMETER_MISSING,
+ "code");
+ }
+ if (NULL == bc->client_secret)
+ {
+ GNUNET_break_op (0);
+ return TALER_MHD_reply_with_error (hc->connection,
+ MHD_HTTP_BAD_REQUEST,
+ TALER_EC_GENERIC_PARAMETER_MISSING,
+ "client_secret");
+ }
+ if (NULL == bc->client_id)
+ {
+ GNUNET_break_op (0);
+ return TALER_MHD_reply_with_error (hc->connection,
+ MHD_HTTP_BAD_REQUEST,
+ TALER_EC_GENERIC_PARAMETER_MISSING,
+ "client_id");
+ }
+ if (NULL == bc->redirect_uri)
+ {
+ GNUNET_break_op (0);
+ return TALER_MHD_reply_with_error (hc->connection,
+ MHD_HTTP_BAD_REQUEST,
+ TALER_EC_GENERIC_PARAMETER_MISSING,
+ "redirect_uri");
+ }
+
+ /* Check this client is authorized to access the service */
+ {
+ enum GNUNET_DB_QueryStatus qs;
+ char *client_url = NULL;
+
+ qs = CH_db->client_check (CH_db->cls,
+ bc->client_id,
+ bc->client_secret,
+ 0, /* do not increment */
+ &client_url);
+ switch (qs)
+ {
+ case GNUNET_DB_STATUS_HARD_ERROR:
+ GNUNET_break (0);
+ return TALER_MHD_reply_with_error (hc->connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_XX,
+ "client_check");
+ case GNUNET_DB_STATUS_SOFT_ERROR:
+ GNUNET_break (0);
+ return GNUNET_NO;
+ case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
+ GNUNET_break_op (0);
+ return TALER_MHD_reply_with_error (hc->connection,
+ MHD_HTTP_NOT_FOUND,
+ TALER_EC_CHALLENGER_XXX,
+ NULL);
+ case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
+ break;
+ }
+ if ( (NULL != client_url) &&
+ (0 != strcmp (client_url,
+ bc->redirect_uri)) )
+ {
+ GNUNET_break_op (0);
+ return TALER_MHD_reply_with_error (hc->connection,
+ MHD_HTTP_FORBIDDEN,
+ TALER_EC_CHALLENGER_XXX,
+ NULL);
+ }
+ GNUNET_free (client_url);
+ }
- /* FIXME: generate proper response */
- return MHD_NO;
+ if (GNUNET_OK !=
+ CH_code_to_nonce (bc->code,
+ &bc->nonce))
+ {
+ GNUNET_break_op (0);
+ return TALER_MHD_reply_with_error (hc->connection,
+ MHD_HTTP_FORBIDDEN,
+ TALER_EC_CHALLENGER_XXX,
+ NULL);
+ }
+
+ /* Check code is valid */
+ {
+ char *client_secret;
+ char *address;
+ char *client_scope;
+ char *client_state;
+ char *client_redirect_url;
+ enum GNUNET_DB_QueryStatus qs;
+ char *code;
+
+ qs = CH_db->validation_get (CH_db->cls,
+ &bc->nonce,
+ &client_secret,
+ &address,
+ &client_scope,
+ &client_state,
+ &client_redirect_url);
+ switch (qs)
+ {
+ case GNUNET_DB_STATUS_HARD_ERROR:
+ GNUNET_break (0);
+ return TALER_MHD_reply_with_error (hc->connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_XX,
+ "validation_get");
+ case GNUNET_DB_STATUS_SOFT_ERROR:
+ GNUNET_break (0);
+ return GNUNET_NO;
+ case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
+ GNUNET_break_op (0);
+ return TALER_MHD_reply_with_error (hc->connection,
+ MHD_HTTP_NOT_FOUND,
+ TALER_EC_CHALLENGER_XXX,
+ "validation_get");
+ case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
+ break;
+ }
+ code = CH_compute_code (&bc->nonce,
+ client_secret,
+ client_scope,
+ address,
+ client_redirect_url);
+ GNUNET_free (address);
+ GNUNET_free (client_scope);
+ GNUNET_free (client_secret);
+ GNUNET_free (client_redirect_url);
+ GNUNET_free (client_state);
+ if (0 != strcmp (code,
+ bc->code))
+ {
+ GNUNET_break_op (0);
+ GNUNET_free (code);
+ return TALER_MHD_reply_with_error (hc->connection,
+ MHD_HTTP_FORBIDDEN,
+ TALER_EC_CHALLENGER_XXX,
+ "code");
+ }
+ GNUNET_free (code);
+ }
+
+ {
+ struct CHALLENGER_AccessTokenP grant;
+ enum GNUNET_DB_QueryStatus qs;
+ /* FIXME: do not hard-code 1h? */
+ struct GNUNET_TIME_Relative expiration
+ = GNUNET_TIME_UNIT_HOURS;
+
+ GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
+ &grant,
+ sizeof (grant));
+ qs = CH_db->auth_add_grant (CH_db->cls,
+ &bc->nonce,
+ &grant,
+ expiration);
+ switch (qs)
+ {
+ case GNUNET_DB_STATUS_HARD_ERROR:
+ GNUNET_break (0);
+ return TALER_MHD_reply_with_error (hc->connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_XX,
+ "add_grant");
+ case GNUNET_DB_STATUS_SOFT_ERROR:
+ GNUNET_break (0);
+ return GNUNET_NO;
+ case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
+ GNUNET_break (0);
+ return TALER_MHD_reply_with_error (hc->connection,
+ MHD_HTTP_NOT_FOUND,
+ TALER_EC_CHALLENGER_XXX,
+ "add_grant");
+ case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
+ break;
+ }
+
+
+ return TALER_MHD_REPLY_JSON_PACK (
+ hc->connection,
+ MHD_HTTP_OK,
+ GNUNET_JSON_pack_data_auto ("access_token",
+ &grant),
+ GNUNET_JSON_pack_string ("token_type",
+ "Bearer"),
+ GNUNET_JSON_pack_uint64 ("expires_in",
+ expiration.rel_time_us
+ / GNUNET_TIME_UNIT_SECONDS.rel_time_us));
+ }
}
diff --git a/src/challenger/challenger-httpd_challenge.c
b/src/challenger/challenger-httpd_challenge.c
index cf45cb5..1cfaa44 100644
--- a/src/challenger/challenger-httpd_challenge.c
+++ b/src/challenger/challenger-httpd_challenge.c
@@ -34,6 +34,36 @@
struct ChallengeContext
{
+ /**
+ * Nonce of the operation.
+ */
+ struct CHALLENGER_ValidationNonceP nonce;
+
+ /**
+ * Kept in a DLL.
+ */
+ struct ChallengeContext *next;
+
+ /**
+ * Kept in a DLL.
+ */
+ struct ChallengeContext *prev;
+
+ /**
+ * Our handler context.
+ */
+ struct CH_HandlerContext *hc;
+
+ /**
+ * Handle to the helper process.
+ */
+ struct GNUNET_OS_Process *child;
+
+ /**
+ * Handle to wait for @e child
+ */
+ struct GNUNET_ChildWaitHandle *cwh;
+
/**
* Handle for processing uploaded data.
*/
@@ -44,13 +74,90 @@ struct ChallengeContext
*/
char *address;
+ /**
+ * When did we transmit last?
+ */
+ struct GNUNET_TIME_Absolute last_tx_time;
+
+ /**
+ * Exit code from helper.
+ */
+ unsigned long int exit_code;
+
/**
* Number of bytes in @a address, excluding 0-terminator.
*/
size_t address_len;
+
+ /**
+ * Our tan.
+ */
+ uint32_t tan;
+
+ /**
+ * How many attempts does the user have left?
+ */
+ uint32_t pin_attempts_left;
+
+ /**
+ * How did the helper die?
+ */
+ enum GNUNET_OS_ProcessStatusType pst;
+
+ /**
+ * Connection status. #GNUNET_OK to continue
+ * normally, #GNUNET_NO if an error was already
+ * returned, #GNUNET_SYSERR if we failed to
+ * return an error and should just return #MHD_NO.
+ */
+ enum GNUNET_GenericReturnValue status;
+
+ /**
+ * #GNUNET_YES if we are suspended in #bc_head,
+ * #GNUNET_NO if operating normally,
+ * #GNUNET_SYSERR if resumed by shutdown (end with #MHD_NO)
+ */
+ enum GNUNET_GenericReturnValue suspended;
+
+ /**
+ * Should we retransmit the PIN?
+ */
+ bool retransmit;
+
+ /**
+ * Did we do the DB interaction?
+ */
+ bool db_finished;
};
+/**
+ * Head of suspended challenger contexts.
+ */
+struct ChallengeContext *bc_head;
+
+/**
+ * Tail of suspended challenger contexts.
+ */
+struct ChallengeContext *bc_tail;
+
+
+void
+CH_wakeup_challenge_on_shutdown ()
+{
+ struct ChallengeContext *bc;
+
+ while (NULL != (bc = bc_head))
+ {
+ GNUNET_CONTAINER_DLL_remove (bc_head,
+ bc_tail,
+ bc);
+ MHD_resume_connection (bs->connection);
+ bc->suspended = GNUNET_SYSERR;
+ }
+}
+
+
/**
* Function called to clean up a backup context.
*
@@ -66,11 +173,153 @@ cleanup_ctx (void *cls)
GNUNET_break_op (MHD_YES ==
MHD_destroy_post_processor (bc->pp));
}
+ if (NULL != bc->cwh)
+ {
+ GNUNET_wait_child_cancel (bc->cwh);
+ bc->cwh = NULL;
+ }
+ if (NULL != bc->child)
+ {
+ (void) GNUNET_OS_process_kill (bc->child,
+ SIGKILL);
+ GNUNET_break (GNUNET_OK ==
+ GNUNET_OS_process_wait (bc->child));
+ bc->child = NULL;
+ }
GNUNET_free (bc->address);
GNUNET_free (bc);
}
+/**
+ * Function called when our PIN transmission helper has terminated.
+ *
+ * @param cls our `struct ChallengeContext *`
+ * @param type type of the process
+ * @param exit_code status code of the process
+ */
+static void
+child_done_cb (void *cls,
+ enum GNUNET_OS_ProcessStatusType type,
+ long unsigned int exit_code)
+{
+ struct ChallengeContext *bc = cls;
+
+ bc->child = NULL;
+ bc->cwh = NULL;
+ bc->pst = type;
+ bc->exit_code = exit_code;
+ MHD_resume_connection (bs->connection);
+ GNUNET_CONTAINER_DLL_remove (bc_head,
+ bc_tail,
+ bc);
+ CH_trigger_daemon ();
+}
+
+
+/**
+ * Transmit the TAN to the given address.
+ *
+ * @param[in,out] bc context to submit TAN for
+ * @param tan TAN value to submit
+ */
+static void
+send_tan (struct ChallengeContext *bc,
+ uint32_t tan)
+{
+ struct GNUNET_DISK_PipeHandle *p;
+ struct GNUNET_DISK_FileHandle *pipe_stdin;
+ char *msg;
+
+ p = GNUNET_DISK_pipe (GNUNET_DISK_PF_BLOCKING_RW);
+ if (NULL == p)
+ {
+ MHD_STATUS mres;
+
+ // FIXME: generate HTML error instead...
+ mres = TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_CHALLENGER_HELPER_EXEC_FAILED,
+ "pipe");
+ bc->status = (MHD_YES == mres)
+ ? GNUNET_NO
+ : GNUNET_SYSERR;
+ return;
+ }
+ bc->child = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_ERR,
+ p,
+ NULL,
+ NULL,
+ CH_auth_command,
+ CH_auth_command,
+ bc->address,
+ NULL);
+ if (NULL == child)
+ {
+ MHD_RESULT mres;
+
+ GNUNET_DISK_pipe_close (p);
+ // FIXME: generate HTML error instead...
+ mres = TALER_MHD_reply_with_error (bc->hc->connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_CHALLENGER_HELPER_EXEC_FAILED,
+ "exec");
+ bc->status = (MHD_YES == mres)
+ ? GNUNET_NO
+ : GNUNET_SYSERR;
+ return;
+ }
+ pipe_stdin = GNUNET_DISK_pipe_detach_end (p,
+ GNUNET_DISK_PIPE_END_WRITE);
+ GNUNET_assert (NULL != pipe_stdin);
+ GNUNET_DISK_pipe_close (p);
+
+ GNUNET_asprintf (&msg,
+ "PIN: %u",
+ (unsigned int) pin);
+ {
+ const char *off = msg;
+ size_t left = strlen (off);
+
+ while (0 != left)
+ {
+ ssize_t ret;
+
+ if (0 == left)
+ break;
+ ret = GNUNET_DISK_file_write (pipe_stdin,
+ off,
+ left);
+ if (ret <= 0)
+ {
+ MHD_RESULT mres;
+
+ // FIXME: generate HTML error instead...
+ mres = TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+
TALER_EC_CHALLENGER_HELPER_EXEC_FAILED,
+ "write");
+ bc->status = (MHD_YES == mres)
+ ? GNUNET_NO
+ : GNUNET_SYSERR;
+ return;
+ }
+ msg_off += ret;
+ off += ret;
+ left -= ret;
+ }
+ GNUNET_DISK_file_close (pipe_stdin);
+ }
+ bc->cwh = GNUNET_wait_child (bc->child,
+ &child_done_cb,
+ bc);
+ MHD_suspend_connection (connection);
+ GNUNET_CONTAINER_DLL_insert (bc_head,
+ bc_tail,
+ bc);
+}
+
+
/**
* Iterator over key-value pairs where the value may be made available
* in increments and/or may not be zero-terminated. Used for
@@ -128,33 +377,60 @@ CH_handler_challenge (struct CH_HandlerContext *hc,
size_t *upload_data_size)
{
struct ChallengeContext *bc = hc->ctx;
- struct CHALLENGER_ValidationNonceP nonce;
- if (GNUNET_OK !=
- GNUNET_STRINGS_string_to_data (hc->path,
- strlen (hc->path),
- &nonce,
- sizeof (nonce)))
- {
- GNUNET_break_op (0);
- return TALER_MHD_reply_with_error (hc->connection,
- MHD_HTTP_NOT_FOUND,
- TALER_EC_GENERIC_PARAMETER_MISSING,
- hc->path);
- }
if (NULL == bc)
{
/* first call, setup internals */
bc = GNUNET_new (struct ChallengeContext);
+ bc->status = GNUNET_OK;
+ bc->hc = hc;
hc->cc = &cleanup_ctx;
hc->ctx = bc;
+ bc->pst = GNUNET_OS_PROCESS_UNKNOWN;
+ bc->tan
+ = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
+ 100000000);
bc->pp = MHD_create_post_processor (hc->connection,
1024,
&post_iter,
bc);
+ if (GNUNET_OK !=
+ GNUNET_STRINGS_string_to_data (hc->path,
+ strlen (hc->path),
+ &bc->nonce,
+ sizeof (bc->nonce)))
+ {
+ GNUNET_break_op (0);
+ // FIXME: generate HTML error instead...
+ return TALER_MHD_reply_with_error (hc->connection,
+ MHD_HTTP_NOT_FOUND,
+ TALER_EC_GENERIC_PARAMETER_MISSING,
+ hc->path);
+ }
/* FIXME: check content-length is low-enough */
return MHD_YES;
}
+ GNUNET_assert (GNUNET_YES != bc->suspended);
+ if (GNUNET_SYSERR == bc->suspended)
+ return MHD_NO;
+ /* Handle case where helper process failed */
+ if ( ( (GNUNET_OS_PROCESS_UNKNOWN != bc->pst) &&
+ (GNUNET_OS_PROCESS_EXITED != bc->pst) ) ||
+ (0 != bc->exit_code) )
+ {
+ char es[32];
+
+ GNUNET_snprintf (es,
+ sizeof (es),
+ "%u/%d",
+ (unsigned int) bc->exit_code,
+ bc->pst);
+ // FIXME: generate HTML error instead...
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_CHALLENGER_HELPER_EXEC_FAILED,
+ es);
+ }
/* handle upload */
if (0 != *upload_data_size)
{
@@ -166,30 +442,23 @@ CH_handler_challenge (struct CH_HandlerContext *hc,
*upload_data_size = 0;
if (MHD_YES == res)
return MHD_YES;
- /* FIXME: return more specific error if possible... */
return MHD_NO;
}
-
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Submitted address is `%s'\n",
+ bc->address);
+ if (! bc->db_finished)
{
- struct GNUNET_TIME_Absolute last_tx_time
- = GNUNET_TIME_absolute_get ();
- uint32_t last_pin
- = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
- 100000000);
- uint32_t pin_attempts_left = 3; /* if addr is new */
enum GNUNET_DB_QueryStatus qs;
- struct GNUNET_TIME_Absolute next_tx_time;
- bool retransmit;
- next_tx_time = GNUNET_TIME_absolute_subtract (last_tx_time,
- CH_validation_duration);
qs = db->challenge_set_address_and_pin (db->cls,
&nonce,
bc->address,
- next_tx_time,
- &last_tx_time,
- &last_pin,
- &retransmit);
+ CH_validation_duration,
+ &bc->tan,
+ &bc->last_tx_time,
+ &bc->pin_attempts_left,
+ &bc->retransmit);
switch (qs)
{
case GNUNET_DB_STATUS_HARD_ERROR:
@@ -241,7 +510,8 @@ CH_handler_challenge (struct CH_HandlerContext *hc,
case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
break;
}
- if (0 == pin_attempts_left)
+ bc->db_finished = true;
+ if (0 == bc->pin_attempts_left)
{
enum GNUNET_GenericReturnValue ret;
json_t *root = json_object ();
@@ -263,35 +533,52 @@ CH_handler_challenge (struct CH_HandlerContext *hc,
return MHD_YES;
}
- if (retransmit)
+ if (bc->retransmit)
{
- /* Retransmit PIN */
+ /* (Re)transmit PIN/TAN */
+ send_tan (bc,
+ tan);
+ if (GNUNET_YES == bc->suspended)
+ return MHD_YES;
+ /* Did we already try to generate a response? */
+ if (GNUNET_OK != bc->status)
+ return (GNUNET_NO == bc->status)
+ ? MHD_YES
+ : MHD_NO;
}
- {
- json_t *args;
- enum GNUNET_GenericReturnValue ret;
+ }
- args = GNUNET_JSON_PACK (
- GNUNET_JSON_pack_uint64 ("attempts_left",
- pin_attempts_left),
- GNUNET_JSON_pack_timestamp ("next_tx_time",
- GNUNET_TIME_absolute_to_timestamp (
- next_tx_time))
- );
- ret = TALER_TEMPLATING_reply (hc->connection,
- MHD_HTTP_OK,
- "enter-pin-form.must",
- NULL,
- NULL,
- args);
- json_decref (args);
- if (GNUNET_SYSERR == ret)
- {
- GNUNET_break (0);
- return MHD_NO;
- }
- GNUNET_break (GNUNET_OK == ret);
- return MHD_YES;
+ {
+ json_t *args;
+ enum GNUNET_GenericReturnValue ret;
+
+ args = GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_uint64 ("attempts_left",
+ bc->pin_attempts_left),
+ GNUNET_JSON_pack_string ("nonce",
+ hc->path),
+ GNUNET_JSON_pack_string ("address",
+ bc->address),
+ GNUNET_JSON_pack_bool ("transmitted",
+ bc->retransmit),
+ GNUNET_JSON_pack_string ("next_tx_time",
+ GNUNET_TIME_absolute2s (
+ GNUNET_TIME_absolute_to_timestamp (
+ bc->next_tx_time)))
+ );
+ ret = TALER_TEMPLATING_reply (hc->connection,
+ MHD_HTTP_OK,
+ "enter-tan-form.must",
+ NULL,
+ NULL,
+ args);
+ json_decref (args);
+ if (GNUNET_SYSERR == ret)
+ {
+ GNUNET_break (0);
+ return MHD_NO;
}
+ GNUNET_break (GNUNET_OK == ret);
+ return MHD_YES;
}
}
diff --git a/src/challenger/challenger-httpd_challenge.h
b/src/challenger/challenger-httpd_challenge.h
index f3f0d7b..c30f03c 100644
--- a/src/challenger/challenger-httpd_challenge.h
+++ b/src/challenger/challenger-httpd_challenge.h
@@ -24,6 +24,13 @@
#include <microhttpd.h>
+/**
+ * Wake up suspended connections during shutdown.
+ */
+void
+CH_wakeup_challenge_on_shutdown (void);
+
+
/**
* Handle a client POSTing a /challenge request
*
diff --git a/src/challenger/challenger-httpd_common.c
b/src/challenger/challenger-httpd_common.c
index e79964e..56df4f3 100644
--- a/src/challenger/challenger-httpd_common.c
+++ b/src/challenger/challenger-httpd_common.c
@@ -53,3 +53,36 @@ CH_get_client_secret (struct MHD_Connection *connection)
}
return tok;
}
+
+
+char *
+CH_compute_code (const struct CHALLENGER_ValidationNonceP *nonce,
+ const char *client_secret,
+ const char *client_scope,
+ const char *address,
+ const char *client_redirect_url)
+{
+ // FIXME: compute HKDF over inputs here!!!
+ GNUNET_break (0); // FIXME: insecure!
+ return "access-granted";
+}
+
+
+enum GNUNET_GenericReturnValue
+CH_code_to_nonce (const char *code,
+ struct CHALLENGER_ValidationNonceP *nonce)
+{
+ GNUNET_break (0); // FIXME: not implemented
+ return GNUNET_SYSERR;
+}
+
+
+char *
+CH_compute_token (const struct CHALLENGER_ValidationNonceP *nonce,
+ const char *client_secret,
+ const char *client_redirect_url)
+{
+ // FIXME: compute HKDF over inputs here!!!
+ GNUNET_break (0); // FIXME: insecure!
+ return "grant-token";
+}
diff --git a/src/challenger/challenger-httpd_common.h
b/src/challenger/challenger-httpd_common.h
index ca213fc..433e070 100644
--- a/src/challenger/challenger-httpd_common.h
+++ b/src/challenger/challenger-httpd_common.h
@@ -34,4 +34,36 @@ const char *
CH_get_client_secret (struct MHD_Connection *connection);
+/**
+ * Compute code that would authorize access to the
+ * given challenge address. NOTE: We may not want
+ * to include all of these when hashing...
+ *
+ * @param nonce nonce of the challenge process
+ * @param client_secret secret of the client that should receive access
+ * @param client_scope scope of the grant
+ * @param address address that access is being granted to
+ * @param client_redirect_url redirect URL of the client
+ * @return code that grants access
+ */
+char *
+CH_compute_code (const struct CHALLENGER_ValidationNonceP *nonce,
+ const char *client_secret,
+ const char *client_scope,
+ const char *address,
+ const char *client_redirect_url);
+
+
+/**
+ * Extracts a @a nonce from the given @a code.
+ *
+ * @param code access code computed via #CH_compute_code()
+ * @param[out] nonce set to nonce used in #CH_compute_code()
+ * @return #GNUNET_OK on success
+ */
+enum GNUNET_GenericReturnValue
+CH_code_to_nonce (const char *code,
+ struct CHALLENGER_ValidationNonceP *nonce);
+
+
#endif
diff --git a/src/challenger/challenger-httpd_info.c
b/src/challenger/challenger-httpd_info.c
index 04a8b47..7d48094 100644
--- a/src/challenger/challenger-httpd_info.c
+++ b/src/challenger/challenger-httpd_info.c
@@ -23,14 +23,97 @@
#include <gnunet/gnunet_util_lib.h>
#include "challenger-httpd_info.h"
+/**
+ * Prefix of a 'Bearer' token in an 'Authorization' HTTP header.
+ */
+#define BEARER_PREFIX "Bearer "
+
MHD_RESULT
CH_handler_info (struct CH_HandlerContext *hc,
const char *upload_data,
size_t *upload_data_size)
{
- return TALER_MHD_reply_with_error (hc->connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
-
TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
- NULL);
+ const char *auth;
+ const char *token;
+ struct CHALLENGER_AccessTokenP grant;
+
+ auth = MHD_lookup_connection_value (hc->connection,
+ MHD_HEADER_KIND,
+ MHD_HTTP_HEADER_AUTHORIZATION);
+ if (NULL == auth)
+ {
+ GNUNET_break_op (0);
+ return TALER_MHD_reply_with_error (hc->connection,
+ MHD_HTTP_FORBIDDEN,
+ TALER_EC_GENERIC_PARAMETER_MISSING,
+ MHD_HTTP_HEADER_AUTHORIZATION);
+ }
+ if (0 != strncmp (auth,
+ BEARER_PREFIX,
+ strlen (BEARER_PREFIX)))
+ {
+ GNUNET_break_op (0);
+ return TALER_MHD_reply_with_error (hc->connection,
+ MHD_HTTP_FORBIDDEN,
+ TALER_EC_GENERIC_PARAMETER_MALFORMED,
+ MHD_HTTP_HEADER_AUTHORIZATION);
+ }
+ token = auth + strlen (BEARER_PREFIX);
+
+ if (GNUNET_OK !=
+ CH_token_to_grant (token,
+ &grant))
+ {
+ GNUNET_break_op (0);
+ return TALER_MHD_reply_with_error (hc->connection,
+ MHD_HTTP_FORBIDDEN,
+ TALER_EC_GENERIC_PARAMETER_MALFORMED,
+ MHD_HTTP_HEADER_AUTHORIZATION);
+ }
+
+ /* Check token is valid */
+ {
+ char *address;
+ enum GNUNET_DB_QueryStatus qs;
+ struct GNUNET_TIME_Timestamp address_expiration;
+ MHD_RESULT mret;
+
+ qs = CH_db->info_get_grant (CH_db->cls,
+ &bc->grant,
+ &address,
+ &address_expiration);
+ switch (qs)
+ {
+ case GNUNET_DB_STATUS_HARD_ERROR:
+ GNUNET_break (0);
+ return TALER_MHD_reply_with_error (hc->connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_XX,
+ "info_get_grant");
+ case GNUNET_DB_STATUS_SOFT_ERROR:
+ GNUNET_break (0);
+ return GNUNET_NO;
+ case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
+ GNUNET_break (0);
+ return TALER_MHD_reply_with_error (hc->connection,
+ MHD_HTTP_FORBIDDEN,
+ TALER_EC_CHALLENGER_XXX,
+ "info_get_grant");
+ case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
+ break;
+ }
+
+ mret = TALER_MHD_REPLY_JSON_PACK (
+ hc->connection,
+ MHD_HTTP_OK,
+ GNUNET_JSON_pack_string ("address",
+ address),
+ GNUNET_JSON_pack_string ("address_type",
+ CH_address_type),
+ GNUNET_JSON_pack_timestamp ("expires",
+ address_expiration));
+ GNUNET_free (address);
+ return mret;
+ }
}
diff --git a/src/challenger/challenger-httpd_login.c
b/src/challenger/challenger-httpd_login.c
index d7273c9..ff8ead9 100644
--- a/src/challenger/challenger-httpd_login.c
+++ b/src/challenger/challenger-httpd_login.c
@@ -68,7 +68,7 @@ CH_handler_login (struct CH_HandlerContext *hc,
return TALER_MHD_reply_with_error (hc->connection,
MHD_HTTP_BAD_REQUEST,
TALER_EC_GENERIC_PARAMETER_MALFORMED,
- "response_type (mus be 'code')");
+ "response_type (must be 'code')");
}
{
@@ -127,7 +127,6 @@ CH_handler_login (struct CH_HandlerContext *hc,
= MHD_lookup_connection_value (hc->connection,
MHD_GET_ARGUMENT_KIND,
"scope");
- (void) scope; /* ignored */
{
char *last_address;
uint32_t address_attempts_left;
@@ -199,6 +198,8 @@ CH_handler_login (struct CH_HandlerContext *hc,
args = GNUNET_JSON_PACK (
GNUNET_JSON_pack_bool ("fix_address",
0 == address_attempts_left),
+ GNUNET_JSON_pack_string ("nonce",
+ hc->path),
GNUNET_JSON_pack_string ("last_address",
last_address),
GNUNET_JSON_pack_uint64 ("changes_left",
diff --git a/src/challenger/challenger-httpd_solve.c
b/src/challenger/challenger-httpd_solve.c
index 0d5c436..8c6631d 100644
--- a/src/challenger/challenger-httpd_solve.c
+++ b/src/challenger/challenger-httpd_solve.c
@@ -33,6 +33,11 @@
struct SolveContext
{
+ /**
+ * Nonce of the operation.
+ */
+ struct CHALLENGER_ValidationNonceP nonce;
+
/**
* Handle for processing uploaded data.
*/
@@ -127,20 +132,7 @@ CH_handler_solve (struct CH_HandlerContext *hc,
size_t *upload_data_size)
{
struct SolveContext *bc = hc->ctx;
- struct CHALLENGER_ValidationNonceP nonce;
- if (GNUNET_OK !=
- GNUNET_STRINGS_string_to_data (hc->path,
- strlen (hc->path),
- &nonce,
- sizeof (nonce)))
- {
- GNUNET_break_op (0);
- return TALER_MHD_reply_with_error (hc->connection,
- MHD_HTTP_NOT_FOUND,
- TALER_EC_GENERIC_PARAMETER_MISSING,
- hc->path);
- }
if (NULL == bc)
{
/* first call, setup internals */
@@ -151,6 +143,18 @@ CH_handler_solve (struct CH_HandlerContext *hc,
1024,
&post_iter,
bc);
+ if (GNUNET_OK !=
+ GNUNET_STRINGS_string_to_data (hc->path,
+ strlen (hc->path),
+ &bc->nonce,
+ sizeof (bc->nonce)))
+ {
+ GNUNET_break_op (0);
+ return TALER_MHD_reply_with_error (hc->connection,
+ MHD_HTTP_NOT_FOUND,
+ TALER_EC_GENERIC_PARAMETER_MISSING,
+ hc->path);
+ }
/* FIXME: check content-length is low-enough */
return MHD_YES;
}
@@ -165,12 +169,251 @@ CH_handler_solve (struct CH_HandlerContext *hc,
*upload_data_size = 0;
if (MHD_YES == res)
return MHD_YES;
- /* FIXME: return more specific error if possible... */
return MHD_NO;
}
- /* FIXME: convert pin string to number */
- /* FIXME: check with DB ... */
+ {
+ unsigned int pin;
+ char dummy;
+ enum GNUNET_DB_QueryStatus qs;
+ bool solved;
+
+ if (1 != sscanf (bc->pin,
+ "%u%c",
+ &pin,
+ &dummy))
+ {
+ enum GNUNET_GenericReturnValue ret;
+ json_t *root = json_object ();
+
+ GNUNET_assert (NULL != root);
+ GNUNET_break_op (0);
+ ret = TALER_TEMPLATING_reply (hc->connection,
+ MHD_HTTP_BAD_REQUEST,
+ "pin-must-be-number.must",
+ NULL,
+ NULL,
+ root);
+ json_decref (root);
+ if (GNUNET_SYSERR == ret)
+ {
+ GNUNET_break (0);
+ return MHD_NO;
+ }
+ GNUNET_break (GNUNET_OK == ret);
+ return MHD_YES;
+ }
+
+ qs = CH_db->validate_solve_pin (CH_db->cls,
+ &bc->nonce,
+ pin,
+ &solved);
+ switch (qs)
+ {
+ case GNUNET_DB_STATUS_HARD_ERROR:
+ {
+ enum GNUNET_GenericReturnValue ret;
+ json_t *root = json_object ();
+
+ GNUNET_assert (NULL != root);
+ GNUNET_break (0);
+ ret = TALER_TEMPLATING_reply (hc->connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ "internal-server-error.must",
+ NULL,
+ NULL,
+ root);
+ json_decref (root);
+ if (GNUNET_SYSERR == ret)
+ {
+ GNUNET_break (0);
+ return MHD_NO;
+ }
+ GNUNET_break (GNUNET_OK == ret);
+ return MHD_YES;
+ }
+ case GNUNET_DB_STATUS_SOFT_ERROR:
+ GNUNET_break (0);
+ return GNUNET_NO;
+ case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
+ {
+ enum GNUNET_GenericReturnValue ret;
+ json_t *root = json_object ();
+
+ GNUNET_assert (NULL != root);
+ ret = TALER_TEMPLATING_reply (hc->connection,
+ MHD_HTTP_NOT_FOUND,
+ "validation-unknown.must",
+ NULL,
+ NULL,
+ root);
+ json_decref (root);
+ if (GNUNET_SYSERR == ret)
+ {
+ GNUNET_break (0);
+ return MHD_NO;
+ }
+ GNUNET_break (GNUNET_OK == ret);
+ return MHD_YES;
+ }
+ case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
+ break;
+ }
+ if (! solved)
+ {
+ enum GNUNET_GenericReturnValue ret;
+ json_t *root = json_object ();
+
+ GNUNET_assert (NULL != root);
+ ret = TALER_TEMPLATING_reply (hc->connection,
+ MHD_HTTP_FORBIDDEN,
+ "invalid-pin.must",
+ NULL,
+ NULL,
+ root);
+ json_decref (root);
+ if (GNUNET_SYSERR == ret)
+ {
+ GNUNET_break (0);
+ return MHD_NO;
+ }
+ GNUNET_break (GNUNET_OK == ret);
+ return MHD_YES;
+ }
+ }
+
+ {
+ struct MHD_Response *response;
+ char *url;
+
+ {
+ char *client_secret;
+ char *address;
+ char *client_scope;
+ char *client_state;
+ char *client_redirect_url;
+ enum GNUNET_DB_QueryStatus qs;
+
+ qs = CH_db->validation_get (CH_db->cls,
+ &bc->nonce,
+ &client_secret,
+ &address,
+ &client_scope,
+ &client_state,
+ &client_redirect_url);
+ switch (qs)
+ {
+ case GNUNET_DB_STATUS_HARD_ERROR:
+ {
+ enum GNUNET_GenericReturnValue ret;
+ json_t *root = json_object ();
- /* FIXME: generate proper response */
- return MHD_NO;
+ GNUNET_assert (NULL != root);
+ GNUNET_break (0);
+ ret = TALER_TEMPLATING_reply (hc->connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ "internal-server-error.must",
+ NULL,
+ NULL,
+ root);
+ json_decref (root);
+ if (GNUNET_SYSERR == ret)
+ {
+ GNUNET_break (0);
+ return MHD_NO;
+ }
+ GNUNET_break (GNUNET_OK == ret);
+ return MHD_YES;
+ }
+ case GNUNET_DB_STATUS_SOFT_ERROR:
+ GNUNET_break (0);
+ return GNUNET_NO;
+ case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
+ {
+ enum GNUNET_GenericReturnValue ret;
+ json_t *root = json_object ();
+
+ GNUNET_assert (NULL != root);
+ ret = TALER_TEMPLATING_reply (hc->connection,
+ MHD_HTTP_NOT_FOUND,
+ "validation-unknown.must",
+ NULL,
+ NULL,
+ root);
+ json_decref (root);
+ if (GNUNET_SYSERR == ret)
+ {
+ GNUNET_break (0);
+ return MHD_NO;
+ }
+ GNUNET_break (GNUNET_OK == ret);
+ return MHD_YES;
+ }
+ case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
+ break;
+ }
+ {
+ char *code;
+ char *ue;
+
+ code = CH_compute_code (&bc->nonce,
+ client_secret,
+ client_scope,
+ address,
+ client_redirect_url);
+ ue = TALER_urlencode (client_state);
+ GNUNET_asprintf (&url,
+ "%s?code=%s&state=%s",
+ client_redirect_url,
+ code,
+ ue);
+ GNUNET_free (ue);
+ GNUNET_free (code);
+ }
+ GNUNET_free (address);
+ GNUNET_free (client_scope);
+ GNUNET_free (client_secret);
+ GNUNET_free (client_redirect_url);
+ GNUNET_free (client_state);
+ }
+
+ {
+ const char *ok = "Ok!";
+
+ response = MHD_create_response_from_buffer (strlen (ok),
+ (void *) ok,
+ MHD_RESPMEM_PERSISTENT);
+ }
+ if (NULL == response)
+ {
+ GNUNET_break (0);
+ GNUNET_free (url);
+ return MHD_NO;
+ }
+ TALER_MHD_add_global_headers (response);
+ GNUNET_break (MHD_YES ==
+ MHD_add_response_header (response,
+ MHD_HTTP_HEADER_CONTENT_TYPE,
+ "text/plain"));
+ if (MHD_NO ==
+ MHD_add_response_header (response,
+ MHD_HTTP_HEADER_LOCATION,
+ url))
+ {
+ GNUNET_break (0);
+ MHD_destroy_response (response);
+ GNUNET_free (url);
+ return MHD_NO;
+ }
+ GNUNET_free (url);
+
+ {
+ MHD_RESULT ret;
+
+ ret = MHD_queue_response (connection,
+ MHD_HTTP_FOUND,
+ response);
+ MHD_destroy_response (response);
+ return ret;
+ }
+ }
}
diff --git a/src/challengerdb/challenger-0001.sql
b/src/challengerdb/challenger-0001.sql
index 5f79f5f..9cf8c8a 100644
--- a/src/challengerdb/challenger-0001.sql
+++ b/src/challengerdb/challenger-0001.sql
@@ -98,7 +98,8 @@ CREATE TABLE IF NOT EXISTS grants
(grant_serial_id BIGINT GENERATED BY DEFAULT AS IDENTITY
,access_token BYTEA PRIMARY KEY CHECK (length(access_token)=32)
,address VARCHAR NOT NULL
- ,expiration_time INT8 NOT NULL
+ ,address_expiration_time INT8 NOT NULL
+ ,grant_expiration_time INT8 NOT NULL
);
COMMENT ON TABLE grants
@@ -107,8 +108,10 @@ COMMENT ON COLUMN grants.access_token
IS 'Token that grants access to the resource (the address)';
COMMENT ON COLUMN grants.address
IS 'Address of the user (the resource protected by the token)';
-COMMENT ON COLUMN grants.expiration_time
- IS 'When will the grant expire';
+COMMENT ON COLUMN grants.address_expiration_time
+ IS 'Timestamp until when we consider the address to be valid';
+COMMENT ON COLUMN grants.grant_expiration_time
+ IS 'Time until when we consider the grnat to be valid';
-- Complete transaction
COMMIT;
diff --git a/src/challengerdb/pg_challenge_set_address_and_pin.c
b/src/challengerdb/pg_challenge_set_address_and_pin.c
index 9ef952d..cf99ec3 100644
--- a/src/challengerdb/pg_challenge_set_address_and_pin.c
+++ b/src/challengerdb/pg_challenge_set_address_and_pin.c
@@ -31,70 +31,82 @@ CH_PG_challenge_set_address_and_pin (
void *cls,
const struct CHALLENGER_ValidationNonceP *nonce,
const char *address,
- struct GNUNET_TIME_Absolute next_tx_time,
+ struct GNUNET_TIME_Relative validation_duration,
+ uint32_t *tan,
struct GNUNET_TIME_Absolute *last_tx_time,
- uint32_t *last_pin,
+ uint32_t *pin_attempts_left,
bool *pin_transmit)
{
struct PostgresClosure *pg = cls;
+ struct GNUNET_TIME_Absolute now
+ = GNUNET_TIME_absolute_get ();
+ struct GNUNET_TIME_Absolute next_tx_time
+ = GNUNET_TIME_absolute_subtract (last_tx_time,
+ validation_duration),
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_auto_from_type (nonce),
GNUNET_PQ_query_param_string (address),
GNUNET_PQ_query_param_absolute_time (&next_tx_time),
- GNUNET_PQ_query_param_absolute_time (last_tx_time),
- GNUNET_PQ_query_param_uint32 (last_pin),
+ GNUNET_PQ_query_param_absolute_time (&now),
+ GNUNET_PQ_query_param_uint32 (tan),
GNUNET_PQ_query_param_end
};
struct GNUNET_PQ_ResultSpec rs[] = {
GNUNET_PQ_result_spec_absolute_time ("last_tx_time",
last_tx_time),
GNUNET_PQ_result_spec_uint32 ("last_pin",
- last_pin),
+ tan),
GNUNET_PQ_result_spec_bool ("pin_transmit",
pin_transmit),
+ GNUNET_PQ_result_spec_uint32 ("pin_attempts_left",
+ pin_attempts_left),
GNUNET_PQ_result_spec_end
};
- // FIXME: review!!!
PREPARE (pg,
"challenge_set_address_and_pin",
+ "WITH decisions AS ("
+ " SELECT "
+ " ,(address != $2) AND"
+ " (address_attempts_left > 0)"
+ " AS addr_changed"
+ " ,(pin_transmissions_left > 0) AND"
+ " ( (address != $2) OR"
+ " (last_tx_time < $3) ) AS send_pin"
+ " FROM validations"
+ " WHERE nonce=$1"
+ ")"
"UPDATE validations SET"
" address_attempts_left=CASE"
- " WHEN address != $2"
- " THEN address_attempts_left - 1"
- " ELSE address_attempts_left"
- " END"
- " ,last_pin=CASE"
- " WHEN address != $2"
- " THEN $5"
- " ELSE last_pin"
- " ,END"
- " ,pin_transmissions_left=CASE"
- " WHEN address != $2"
- " THEN 3"
- " ELSE WHEN last_tx_time < 3"
- " THEN pin_transmissions_left - 1"
- " ELSE pin_transmissions_left"
- " END"
- " ,END"
- " ,last_tx_time=CASE"
- " WHEN last_tx_time < $3"
- " THEN $4"
- " ELSE last_tx_time"
- " END"
- " ,address=$2"
- " WHERE nonce=$1"
- " AND ( (address_attempts_left > 0)"
- " OR ( (address == $2) AND"
- " ( (pin_transmissions_left > 0) OR"
- " (last_tx_time >= $3) ) ) )"
- " RETURNING"
- " last_tx_time"
- " ,(address != $2) OR"
- " ( (pin_transmissions_left > 0) AND"
- " (last_tx_time < $3) ) AS pin_transmit"
- " ,last_pin"
- " ,pin_attempts_left;");
+ " WHEN decisions.addr_changed
+ " THEN address_attempts_left - 1 "
+ " ELSE address_attempts_left "
+ " END "
+ ",last_pin = CASE "
+ " WHEN decisions.addr_changed
+ " THEN $5"
+ " ELSE last_pin"
+ " ,END"
+ " ,pin_transmissions_left=CASE"
+ " WHEN decisions.addr_changed
+ " THEN 3 "
+ " ELSE WHEN decisions.send_pin
+ " THEN pin_transmissions_left - 1"
+ " ELSE pin_transmissions_left"
+ " END"
+ " ,END"
+ " ,last_tx_time=CASE"
+ " WHEN decisions.send_pin"
+ " THEN $4"
+ " ELSE last_tx_time"
+ " END"
+ " ,address=$2"
+ " WHERE nonce=$1"
+ " RETURNING"
+ " last_tx_time"
+ " ,decisions.send_pin AS pin_transmit"
+ " ,last_pin"
+ " ,pin_attempts_left;");
return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
"challenge_set_address_and_pin",
params,
diff --git a/src/challengerdb/pg_challenge_set_address_and_pin.h
b/src/challengerdb/pg_challenge_set_address_and_pin.h
index d817b57..3936c5e 100644
--- a/src/challengerdb/pg_challenge_set_address_and_pin.h
+++ b/src/challengerdb/pg_challenge_set_address_and_pin.h
@@ -35,10 +35,11 @@
* @param cls
* @param nonce unique nonce to use to identify the validation
* @param address the new address to validate
- * @param next_tx_time tx time we must have sent earlier before to retransmit
now
- * @param[in,out] last_tx_time set to the last time when we (presumably) send
a PIN to @a address, input should be current time to use if the existing value
for tx_time is past @a next_tx_time
- * @param[in,out] last_pin set to the PIN last send to @a address, input
should be random PIN to use if address did not change
+ * @param validation_duration minimum time between transmissions
+ * @param[in,out] tan set to the PIN/TAN last send to @a address, input should
be random PIN/TAN to use if address did not change
+ * @param[out] last_tx_time set to the last time when we (presumably) send a
PIN to @a address, input should be current time to use if the existing value
for tx_time is past @a next_tx_time
* @param[out] pin_transmit set to true if we should transmit the @a last_pin
to the @a address
+ * @param[out] pin_attempts_left set to number of attempts the user has left
on this pin
* @return transaction status:
* #GNUNET_DB_SUCCESS_ONE_RESULT if the address was changed
* #GNUNET_DB_SUCCESS_NO_RESULTS if we do not permit further changes to the
address (attempts exhausted)
@@ -49,9 +50,10 @@ CH_PG_challenge_set_address_and_pin (
void *cls,
const struct CHALLENGER_ValidationNonceP *nonce,
const char *address,
- struct GNUNET_TIME_Absolute next_tx_time,
+ struct GNUNET_TIME_Relative validation_duration,
+ uint32_t *tan,
struct GNUNET_TIME_Absolute *last_tx_time,
- uint32_t *last_pin,
+ uint32_t *pin_attempts_left,
bool *pin_transmit);
diff --git a/src/include/challenger_database_plugin.h
b/src/include/challenger_database_plugin.h
index b8c19eb..c3cf1ce 100644
--- a/src/include/challenger_database_plugin.h
+++ b/src/include/challenger_database_plugin.h
@@ -39,6 +39,18 @@ struct CHALLENGER_ValidationNonceP
};
+/**
+ * Nonce to uniquely (and unpredictably) identify grants.
+ */
+struct CHALLENGER_AccessTokenP
+{
+ /**
+ * 256-bit nonce used to identify grants.
+ */
+ uint32_t value[256 / 32];
+};
+
+
/**
* Handle to interact with the database.
*
@@ -244,10 +256,11 @@ struct CHALLENGER_DatabasePlugin
* @param cls closure
* @param nonce unique nonce to use to identify the validation
* @param address the new address to validate
- * @param next_tx_time tx time we must have sent earlier before to
retransmit now
- * @param[in,out] last_tx_time set to the last time when we (presumably)
send a PIN to @a address, input should be current time to use if the existing
value for tx_time is past @a next_tx_time
- * @param[in,out] last_pin set to the PIN last send to @a address, input
should be random PIN to use if address did not change
- * @param[out] pin_transmit set to true if we should transmit @a last_pin to
the @a address
+ * @param validation_duration minimum time between transmissions
+ * @param[in,out] tan set to the PIN/TAN last send to @a address, input
should be random PIN/TAN to use if address did not change
+ * @param[out] last_tx_time set to the last time when we (presumably) send a
PIN to @a address, input should be current time to use if the existing value
for tx_time is past @a next_tx_time
+ * @param[out] pin_transmit set to true if we should transmit the @a
last_pin to the @a address
+ * @param[out] pin_attempts_left set to number of attempts the user has left
on this pin
* @return transaction status:
* #GNUNET_DB_SUCCESS_ONE_RESULT if the address was changed
* #GNUNET_DB_SUCCESS_NO_RESULTS if we do not permit further changes to
the address (attempts exhausted)
@@ -258,9 +271,10 @@ struct CHALLENGER_DatabasePlugin
void *cls,
const struct CHALLENGER_ValidationNonceP *nonce,
const char *address,
- struct GNUNET_TIME_Absolute next_tx_time,
+ struct GNUNET_TIME_Relative validation_duration,
+ uint32_t *tan,
struct GNUNET_TIME_Absolute *last_tx_time,
- uint32_t *last_pin,
+ uint32_t *pin_attempts_left,
bool *pin_transmit);
@@ -310,5 +324,39 @@ struct CHALLENGER_DatabasePlugin
char **client_redirect_url);
+ /**
+ * Add access @a grant to address under @a nonce.
+ *
+ * @param cls closure
+ * @param nonce validation process to grant access to
+ * @param grant grant token that grants access
+ * @param grant_expiration for how long should the grant be valid
+ * @param address_expiration for how long after validation do we consider
addresses to be valid
+ * @return transaction status
+ */
+ enum GNUNET_DB_QueryStatus
+ (*auth_add_grant)(void *cls,
+ const struct CHALLENGER_ValidationNonceP *nonce,
+ const struct CHALLENGER_AccessTokenP *grant,
+ struct GNUNET_TIME_Relative grant_expiration,
+ struct GNUNET_TIME_Relative address_expiration);
+
+
+ /**
+ * Return @a address which @a grant gives access to.
+ *
+ * @param cls closure
+ * @param grant grant token that grants access
+ * @param[out] address set to the address under @a grant
+ * @param[out] address_expiration set to how long we consider @a address to
be valid
+ * @return transaction status
+ */
+ enum GNUNET_DB_QueryStatus
+ (*info_get_grant)(void *cls,
+ const struct CHALLENGER_AccessTokenP *grant,
+ char **address,
+ struct GNUNET_TIME_Timestamp *address_expiration);
+
+
};
#endif
--
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [taler-challenger] branch master updated: -more basic work on challenger,
gnunet <=