summaryrefslogtreecommitdiff
path: root/src/authorization
diff options
context:
space:
mode:
Diffstat (limited to 'src/authorization')
-rw-r--r--src/authorization/Makefile.am31
-rwxr-xr-xsrc/authorization/anastasis-authorization-email.sh1
-rwxr-xr-xsrc/authorization/anastasis-authorization-post.sh196
-rwxr-xr-xsrc/authorization/anastasis-authorization-sms.sh31
-rw-r--r--src/authorization/anastasis_authorization_plugin.c2
-rw-r--r--src/authorization/anastasis_authorization_plugin_email.c76
-rw-r--r--src/authorization/anastasis_authorization_plugin_file.c32
-rw-r--r--src/authorization/anastasis_authorization_plugin_iban.c281
-rw-r--r--src/authorization/anastasis_authorization_plugin_post.c83
-rw-r--r--src/authorization/anastasis_authorization_plugin_sms.c73
-rw-r--r--src/authorization/anastasis_authorization_plugin_totp.c381
-rw-r--r--src/authorization/authorization-email-messages.json4
-rw-r--r--src/authorization/authorization-post-messages.json2
-rw-r--r--src/authorization/iban.h2
-rw-r--r--src/authorization/libanastasiseufin/lae_common.h2
-rw-r--r--src/authorization/libanastasiseufin/lae_credit.c8
-rwxr-xr-xsrc/authorization/test-post.sh12
17 files changed, 922 insertions, 295 deletions
diff --git a/src/authorization/Makefile.am b/src/authorization/Makefile.am
index cfcd89e..5d2854d 100644
--- a/src/authorization/Makefile.am
+++ b/src/authorization/Makefile.am
@@ -21,6 +21,8 @@ pkgdata_DATA = \
EXTRA_DIST = \
$(pkgdata_DATA) \
+ $(cfg_DATA) \
+ $(bin_SCRIPTS) \
iban.h iban.c
@@ -33,7 +35,9 @@ bin_PROGRAMS = \
anastasis-helper-authorization-iban
bin_SCRIPTS = \
- anastasis-authorization-email.sh
+ anastasis-authorization-email.sh \
+ anastasis-authorization-sms.sh \
+ anastasis-authorization-post.sh
anastasis_helper_authorization_iban_SOURCES = \
anastasis-helper-authorization-iban.c
@@ -69,7 +73,8 @@ plugin_LTLIBRARIES = \
libanastasis_plugin_authorization_file.la \
libanastasis_plugin_authorization_iban.la \
libanastasis_plugin_authorization_post.la \
- libanastasis_plugin_authorization_sms.la
+ libanastasis_plugin_authorization_sms.la \
+ libanastasis_plugin_authorization_totp.la
libanastasis_plugin_authorization_file_la_SOURCES = \
@@ -95,6 +100,7 @@ libanastasis_plugin_authorization_email_la_LIBADD = \
libanastasis_plugin_authorization_email_la_LDFLAGS = \
$(ANASTASIS_PLUGIN_LDFLAGS) \
$(top_builddir)/src/stasis/libanastasisdb.la \
+ $(top_builddir)/src/util/libanastasisutil.la \
-ltalerjson \
-ltalermhd \
-ltalerutil \
@@ -127,6 +133,7 @@ libanastasis_plugin_authorization_post_la_LIBADD = \
libanastasis_plugin_authorization_post_la_LDFLAGS = \
$(ANASTASIS_PLUGIN_LDFLAGS) \
$(top_builddir)/src/stasis/libanastasisdb.la \
+ $(top_builddir)/src/util/libanastasisutil.la \
-ltalerjson \
-ltalermhd \
-ltalerutil \
@@ -143,6 +150,25 @@ libanastasis_plugin_authorization_sms_la_LIBADD = \
libanastasis_plugin_authorization_sms_la_LDFLAGS = \
$(ANASTASIS_PLUGIN_LDFLAGS) \
$(top_builddir)/src/stasis/libanastasisdb.la \
+ $(top_builddir)/src/util/libanastasisutil.la \
+ -ltalerjson \
+ -ltalermhd \
+ -ltalerutil \
+ -lgnunetjson \
+ -lgnunetutil \
+ -ljansson \
+ -lmicrohttpd \
+ $(XLIB)
+
+
+libanastasis_plugin_authorization_totp_la_SOURCES = \
+ anastasis_authorization_plugin_totp.c
+libanastasis_plugin_authorization_totp_la_LIBADD = \
+ $(LTLIBINTL)
+libanastasis_plugin_authorization_totp_la_LDFLAGS = \
+ $(ANASTASIS_PLUGIN_LDFLAGS) \
+ $(top_builddir)/src/stasis/libanastasisdb.la \
+ $(top_builddir)/src/util/libanastasisutil.la \
-ltalerjson \
-ltalermhd \
-ltalerutil \
@@ -150,4 +176,5 @@ libanastasis_plugin_authorization_sms_la_LDFLAGS = \
-lgnunetutil \
-ljansson \
-lmicrohttpd \
+ -lgcrypt \
$(XLIB)
diff --git a/src/authorization/anastasis-authorization-email.sh b/src/authorization/anastasis-authorization-email.sh
index ae3ecf7..738aaf0 100755
--- a/src/authorization/anastasis-authorization-email.sh
+++ b/src/authorization/anastasis-authorization-email.sh
@@ -1,2 +1,3 @@
#!/bin/sh
+# This file is in the public domain.
exec mail -s "Anastasis" -r noreply "$1"
diff --git a/src/authorization/anastasis-authorization-post.sh b/src/authorization/anastasis-authorization-post.sh
new file mode 100755
index 0000000..66255ea
--- /dev/null
+++ b/src/authorization/anastasis-authorization-post.sh
@@ -0,0 +1,196 @@
+#!/bin/bash
+# This file is in the public domain.
+set -eu
+
+# Check shared secrets
+if [ -x "$PINGEN_CLIENT_ID" ]
+then
+ echo "PINGEN_CLIENT_ID not sent in environment"
+ exit 1
+fi
+if [ -x "$PINGEN_CLIENT_SECRET" ]
+then
+ echo "PINGEN_CLIENT_SECRET not sent in environment"
+ exit 1
+fi
+if [ -x "$PINGEN_ORG_ID" ]
+then
+ echo "PINGEN_ORG_ID not sent in environment"
+ exit 1
+fi
+
+ENDPOINT="https://api.pingen.com"
+LOGS="$PWD/authorization-post.log"
+
+MESSAGE=$(cat -)
+DATE=$(date +%F)
+ADDR="$1"
+NAME=$(echo $ADDR | jq -r .full_name)
+STREET=$(echo $ADDR | jq -r .street)
+
+LNUMBER=$(echo $STREET | awk '{print $NF}')
+FNUMBER=$(echo $STREET | awk '{print $1}')
+case $LNUMBER in
+ ''|*[!0-9]*)
+ case $FNUMBER in
+ ''|*[!0-9]*)
+ NUMBER=0
+ ;;
+ *)
+ NUMBER=$FNUMBER
+ ;;
+ esac
+ ;;
+ *)
+ NUMBER=$LNUMBER
+ ;;
+esac
+
+
+CITY=$(echo $ADDR | jq -r .city)
+POSTCODE=$(echo $ADDR | jq -r .postcode)
+COUNTRY=$(echo $ADDR | jq -r .country)
+
+MYDIR=$(mktemp -d /tmp/authorization-post-XXXXXX)
+cd "$MYDIR"
+cat - | sed -e "s/%NAME%/$NAME/g" \
+ -e "s/%STREET%/$STREET/g" \
+ -e "s/%POSTCODE%/$POSTCODE/g" \
+ -e "s/%CITY%/$CITY/g" \
+ -e "s/%COUNTRY%/$COUNTRY/g" \
+ -e "s/%MESSAGE%/$MESSAGE/g" > input.tex <<EOF
+\NeedsTeXFormat{LaTeX2e}
+\documentclass[fontsize=11pt,a4paper]{scrlttr2}
+\makeatletter
+\KOMAoptions{foldmarks=off}
+%\@setplength{toaddrvpos}{30mm}
+%\@setplength{toaddrhpos}{130mm}
+%\@setplength{sigbeforevskip}{10mm}
+\makeatother
+\setkomavar{subject}{Anastasis Recovery}
+%\setkomavar{fromname}{Anastasis SARL}
+\setkomavar{signature}{Anastasis SARL}
+\date{\today}
+%\address{Anastasis SARL \\\\ 7 rue de Mondorf \\\\ 5431 Erpeldange}
+%\signature{Anastasis SARL}
+\begin{document}
+\begin{letter}{\ \ %NAME% \\\\ \ \ %STREET% \\\\ \ \ %POSTCODE% %CITY% \\\\ \ \ %COUNTRY% }
+\opening{To whom it may concern,}
+%MESSAGE%
+\closing{Best regards}
+\end{letter}
+\end{document}
+EOF
+pdflatex input.tex > /dev/null 2> /dev/null
+
+REPLY=$(curl -s -X POST -H "Content-Type: application/x-www-form-urlencoded" \
+ --data-urlencode "grant_type=client_credentials" \
+ --data-urlencode "client_id=$PINGEN_CLIENT_ID" \
+ --data-urlencode "client_secret=$PINGEN_CLIENT_SECRET" \
+ --data-urlencode "scope=letter" \
+ https://identity.pingen.com/auth/access-tokens)
+
+ACCESS_TOKEN=$(echo $REPLY | jq -r .access_token)
+
+REPLY=$(curl -s \
+ -X GET "$ENDPOINT/file-upload" \
+ -H "Authorization: Bearer $ACCESS_TOKEN")
+ATTRS=$(echo $REPLY | jq .data.attributes)
+UPLOAD_URL=$(echo $ATTRS | jq -r .url)
+URL_SIG=$(echo $ATTRS | jq -r .url_signature)
+
+curl -s -X PUT -T input.pdf "$UPLOAD_URL"
+
+
+RECIPIENT="$(jq -n '
+ {
+ name: $NAME,
+ street: $STREET,
+ number: $NUMBER,
+ city: $CITY,
+ zip: $POSTCODE,
+ country: $COUNTRY,
+ }' \
+ --arg NAME "$NAME" \
+ --arg STREET "$STREET" \
+ --arg NUMBER "$NUMBER" \
+ --arg CITY "$CITY" \
+ --arg POSTCODE "$POSTCODE" \
+ --arg COUNTRY "$COUNTRY" \
+ )"
+
+SENDER="$(jq -n '
+ {
+ name: "Anastasis SARL",
+ street: "Rue de Mondorf",
+ number: "7",
+ zip: "5421",
+ city: "Erpeldange",
+ country: "LU"
+ }'
+ )"
+
+REQUEST="$(jq -n '
+ { data: {
+ type: "letters",
+ attributes: {
+ file_original_name: "input.pdf",
+ file_url: $UPLOAD_URL,
+ file_url_signature: $URL_SIG,
+ address_position: "left",
+ delivery_product: "cheap",
+ print_mode: "duplex",
+ auto_send: true,
+ print_spectrum: "grayscale"
+ } }
+ }' \
+ --argjson RECIPIENT "$RECIPIENT" \
+ --argjson SENDER "$SENDER" \
+ --arg UPLOAD_URL "$UPLOAD_URL" \
+ --arg URL_SIG "$URL_SIG" \
+ )"
+
+STATUS=$(curl -s --request POST \
+ --url "$ENDPOINT/organisations/${PINGEN_ORG_ID}/letters" \
+ --header 'Content-Type: application/vnd.api+json' \
+ --header "Authorization: Bearer $ACCESS_TOKEN" \
+ -d "$REQUEST" \
+ -o "$MYDIR/final-reply.txt" \
+ -w "%{http_code}" -s)
+cat "$MYDIR/final-reply.txt" >> "$LOGS"
+case $STATUS in
+ 201)
+ ;;
+ *)
+ echo "Failed to add letter: $STATUS" >> "$LOGS"
+ echo "$REPLY"
+ exit 1;
+ ;;
+esac
+LETTER_ID=$(cat "$MYDIR/final-reply.txt" | jq -r .data.id)
+REPLY=$MYDIR/delete-reply.txt
+STATUS=409
+sleep 1;
+while test "$STATUS" = 409;
+do
+ STATUS=$(curl -s --request DELETE \
+ --url "$ENDPOINT/organisations/$PINGEN_ORG_ID/letters/$LETTER_ID" \
+ --header "Authorization: Bearer $ACCESS_TOKEN" \
+ -o "$REPLY" \
+ -w "%{http_code}" -s)
+ case $STATUS in
+ 204)
+ cat "$REPLY" >> "$LOGS"
+ ;;
+ 409)
+ # Happens, likely still in processing...
+ ;;
+ *)
+ echo "Failed to delete letter: $STATUS" >> "$LOGS"
+ ;;
+ esac
+done
+
+rm -r "$MYDIR"
+
+exit 0
diff --git a/src/authorization/anastasis-authorization-sms.sh b/src/authorization/anastasis-authorization-sms.sh
new file mode 100755
index 0000000..c3b1055
--- /dev/null
+++ b/src/authorization/anastasis-authorization-sms.sh
@@ -0,0 +1,31 @@
+#!/bin/bash
+# This file is in the public domain.
+set -eu
+
+# Check shared secrets
+if [ -x "$TELESIGN_AUTH_TOKEN" ]
+then
+ echo "TELESIGN_AUTH_TOKEN not sent in environment"
+ exit 1
+fi
+
+MESSAGE=$(cat -)
+TMPFILE=$(mktemp /tmp/sms-loggingXXXXXX)
+STATUS=$(curl --request POST \
+ --url https://rest-api.telesign.com/v1/messaging \
+ --header 'authorization: Basic $TELESIGN_AUTH_TOKEN' \
+ --header 'content-type: application/x-www-form-urlencoded' \
+ --data account_livecycle_event=transact \
+ --data "message=$MESSAGE" \
+ --data message_type=OTP \
+ --data "phone_number=$1" \
+ -w "%{http_code}" -s -o $TMPFILE)
+case $STATUS in
+ 200|203|250|290|291|295)
+ exit 0;
+ ;;
+ *)
+ exit 1;
+ ;;
+esac
+exit 1
diff --git a/src/authorization/anastasis_authorization_plugin.c b/src/authorization/anastasis_authorization_plugin.c
index c557aa3..7e25c03 100644
--- a/src/authorization/anastasis_authorization_plugin.c
+++ b/src/authorization/anastasis_authorization_plugin.c
@@ -3,7 +3,7 @@
Copyright (C) 2015, 2016, 2021 Anastasis SARL
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
+ terms of the GNU Affero 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
diff --git a/src/authorization/anastasis_authorization_plugin_email.c b/src/authorization/anastasis_authorization_plugin_email.c
index 0eefcc5..7fc97e7 100644
--- a/src/authorization/anastasis_authorization_plugin_email.c
+++ b/src/authorization/anastasis_authorization_plugin_email.c
@@ -3,7 +3,7 @@
Copyright (C) 2019-2021 Anastasis SARL
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
+ terms of the GNU Affero 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
@@ -220,7 +220,7 @@ email_validate (void *cls,
{
if (MHD_NO ==
TALER_MHD_reply_with_error (connection,
- MHD_HTTP_EXPECTATION_FAILED,
+ MHD_HTTP_CONFLICT,
TALER_EC_ANASTASIS_EMAIL_INVALID,
NULL))
return GNUNET_SYSERR;
@@ -296,8 +296,12 @@ email_done_cb (void *cls,
{
struct ANASTASIS_AUTHORIZATION_State *as = cls;
- as->child = NULL;
as->cwh = NULL;
+ if (NULL != as->child)
+ {
+ GNUNET_OS_process_destroy (as->child);
+ as->child = NULL;
+ }
as->pst = type;
as->exit_code = exit_code;
MHD_resume_connection (as->connection);
@@ -310,20 +314,17 @@ email_done_cb (void *cls,
* I.e. start to send SMS or e-mail or launch video identification.
*
* @param as authorization state
- * @param timeout how long do we have to produce a reply
* @param connection HTTP client request (for queuing response, such as redirection to video portal)
* @return state of the request
*/
-static enum ANASTASIS_AUTHORIZATION_Result
-email_process (struct ANASTASIS_AUTHORIZATION_State *as,
- struct GNUNET_TIME_Absolute timeout,
- struct MHD_Connection *connection)
+static enum ANASTASIS_AUTHORIZATION_ChallengeResult
+email_challenge (struct ANASTASIS_AUTHORIZATION_State *as,
+ struct MHD_Connection *connection)
{
MHD_RESULT mres;
const char *mime;
const char *lang;
- (void) timeout;
mime = MHD_lookup_connection_value (connection,
MHD_HEADER_KIND,
MHD_HTTP_HEADER_ACCEPT);
@@ -348,8 +349,8 @@ email_process (struct ANASTASIS_AUTHORIZATION_State *as,
TALER_EC_ANASTASIS_EMAIL_HELPER_EXEC_FAILED,
"pipe");
if (MHD_YES != mres)
- return ANASTASIS_AUTHORIZATION_RES_FAILED_REPLY_FAILED;
- return ANASTASIS_AUTHORIZATION_RES_FAILED;
+ return ANASTASIS_AUTHORIZATION_CRES_FAILED_REPLY_FAILED;
+ return ANASTASIS_AUTHORIZATION_CRES_FAILED;
}
as->child = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_ERR,
p,
@@ -367,27 +368,19 @@ email_process (struct ANASTASIS_AUTHORIZATION_State *as,
TALER_EC_ANASTASIS_EMAIL_HELPER_EXEC_FAILED,
"exec");
if (MHD_YES != mres)
- return ANASTASIS_AUTHORIZATION_RES_FAILED_REPLY_FAILED;
- return ANASTASIS_AUTHORIZATION_RES_FAILED;
+ return ANASTASIS_AUTHORIZATION_CRES_FAILED_REPLY_FAILED;
+ return ANASTASIS_AUTHORIZATION_CRES_FAILED;
}
pipe_stdin = GNUNET_DISK_pipe_detach_end (p,
GNUNET_DISK_PIPE_END_WRITE);
GNUNET_assert (NULL != pipe_stdin);
GNUNET_DISK_pipe_close (p);
- {
- char *tpk;
-
- tpk = GNUNET_STRINGS_data_to_string_alloc (
- &as->truth_uuid,
- sizeof (as->truth_uuid));
- GNUNET_asprintf (&as->msg,
- get_message (as->ctx->messages,
- connection,
- "body"),
- (unsigned long long) as->code,
- tpk);
- GNUNET_free (tpk);
- }
+ GNUNET_asprintf (&as->msg,
+ get_message (as->ctx->messages,
+ connection,
+ "body"),
+ ANASTASIS_pin2s (as->code),
+ ANASTASIS_CRYPTO_uuid2s (&as->truth_uuid));
{
const char *off = as->msg;
@@ -409,8 +402,8 @@ email_process (struct ANASTASIS_AUTHORIZATION_State *as,
TALER_EC_ANASTASIS_EMAIL_HELPER_EXEC_FAILED,
"write");
if (MHD_YES != mres)
- return ANASTASIS_AUTHORIZATION_RES_FAILED_REPLY_FAILED;
- return ANASTASIS_AUTHORIZATION_RES_FAILED;
+ return ANASTASIS_AUTHORIZATION_CRES_FAILED_REPLY_FAILED;
+ return ANASTASIS_AUTHORIZATION_CRES_FAILED;
}
as->msg_off += ret;
off += ret;
@@ -423,14 +416,14 @@ email_process (struct ANASTASIS_AUTHORIZATION_State *as,
as);
as->connection = connection;
MHD_suspend_connection (connection);
- return ANASTASIS_AUTHORIZATION_RES_SUSPENDED;
+ return ANASTASIS_AUTHORIZATION_CRES_SUSPENDED;
}
if (NULL != as->cwh)
{
/* Spurious call, why are we here? */
GNUNET_break (0);
MHD_suspend_connection (connection);
- return ANASTASIS_AUTHORIZATION_RES_SUSPENDED;
+ return ANASTASIS_AUTHORIZATION_CRES_SUSPENDED;
}
if ( (GNUNET_OS_PROCESS_EXITED != as->pst) ||
(0 != as->exit_code) )
@@ -447,8 +440,8 @@ email_process (struct ANASTASIS_AUTHORIZATION_State *as,
TALER_EC_ANASTASIS_EMAIL_HELPER_COMMAND_FAILED,
es);
if (MHD_YES != mres)
- return ANASTASIS_AUTHORIZATION_RES_FAILED_REPLY_FAILED;
- return ANASTASIS_AUTHORIZATION_RES_FAILED;
+ return ANASTASIS_AUTHORIZATION_CRES_FAILED_REPLY_FAILED;
+ return ANASTASIS_AUTHORIZATION_CRES_FAILED;
}
/* Build HTTP response */
@@ -471,12 +464,9 @@ email_process (struct ANASTASIS_AUTHORIZATION_State *as,
user = GNUNET_strndup (as->email,
len);
resp = TALER_MHD_MAKE_JSON_PACK (
- GNUNET_JSON_pack_uint64 ("code",
- TALER_EC_ANASTASIS_TRUTH_CHALLENGE_RESPONSE_REQUIRED),
- GNUNET_JSON_pack_string ("hint",
- TALER_ErrorCode_get_hint (
- TALER_EC_ANASTASIS_TRUTH_CHALLENGE_RESPONSE_REQUIRED)),
- GNUNET_JSON_pack_string ("detail",
+ GNUNET_JSON_pack_string ("challenge_type",
+ "TAN_SENT"),
+ GNUNET_JSON_pack_string ("tan_address_hint",
user));
GNUNET_free (user);
}
@@ -502,12 +492,12 @@ email_process (struct ANASTASIS_AUTHORIZATION_State *as,
"text/plain"));
}
mres = MHD_queue_response (connection,
- MHD_HTTP_FORBIDDEN,
+ MHD_HTTP_OK,
resp);
MHD_destroy_response (resp);
if (MHD_YES != mres)
- return ANASTASIS_AUTHORIZATION_RES_SUCCESS_REPLY_FAILED;
- return ANASTASIS_AUTHORIZATION_RES_SUCCESS;
+ return ANASTASIS_AUTHORIZATION_CRES_SUCCESS_REPLY_FAILED;
+ return ANASTASIS_AUTHORIZATION_CRES_SUCCESS;
}
}
@@ -606,7 +596,7 @@ libanastasis_plugin_authorization_email_init (void *cls)
plugin->cls = ctx;
plugin->validate = &email_validate;
plugin->start = &email_start;
- plugin->process = &email_process;
+ plugin->challenge = &email_challenge;
plugin->cleanup = &email_cleanup;
if (GNUNET_OK !=
diff --git a/src/authorization/anastasis_authorization_plugin_file.c b/src/authorization/anastasis_authorization_plugin_file.c
index 66dbbe1..2f4fcb4 100644
--- a/src/authorization/anastasis_authorization_plugin_file.c
+++ b/src/authorization/anastasis_authorization_plugin_file.c
@@ -3,7 +3,7 @@
Copyright (C) 2019 Anastasis SARL
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
+ terms of the GNU Affero 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
@@ -86,7 +86,7 @@ file_validate (void *cls,
(void) cls;
if (NULL == data)
- return GNUNET_NO;
+ return GNUNET_SYSERR;
filename = GNUNET_STRINGS_data_to_string_alloc (data,
data_length);
flag = false;
@@ -100,7 +100,7 @@ file_validate (void *cls,
}
}
if (flag)
- return GNUNET_NO;
+ return GNUNET_SYSERR;
GNUNET_free (filename);
return GNUNET_OK;
}
@@ -161,14 +161,12 @@ file_start (void *cls,
* I.e. start to send SMS or e-mail or launch video identification.
*
* @param as authorization state
- * @param timeout how long do we have to produce a reply
* @param connection HTTP client request (for queuing response, such as redirection to video portal)
* @return state of the request
*/
-static enum ANASTASIS_AUTHORIZATION_Result
-file_process (struct ANASTASIS_AUTHORIZATION_State *as,
- struct GNUNET_TIME_Absolute timeout,
- struct MHD_Connection *connection)
+static enum ANASTASIS_AUTHORIZATION_ChallengeResult
+file_challenge (struct ANASTASIS_AUTHORIZATION_State *as,
+ struct MHD_Connection *connection)
{
const char *mime;
const char *lang;
@@ -201,8 +199,8 @@ file_process (struct ANASTASIS_AUTHORIZATION_State *as,
resp);
MHD_destroy_response (resp);
if (MHD_YES != mres)
- return ANASTASIS_AUTHORIZATION_RES_FAILED_REPLY_FAILED;
- return ANASTASIS_AUTHORIZATION_RES_FAILED;
+ return ANASTASIS_AUTHORIZATION_CRES_FAILED_REPLY_FAILED;
+ return ANASTASIS_AUTHORIZATION_CRES_FAILED;
}
/* print challenge code to file */
@@ -221,8 +219,8 @@ file_process (struct ANASTASIS_AUTHORIZATION_State *as,
resp);
MHD_destroy_response (resp);
if (MHD_YES != mres)
- return ANASTASIS_AUTHORIZATION_RES_FAILED_REPLY_FAILED;
- return ANASTASIS_AUTHORIZATION_RES_FAILED;
+ return ANASTASIS_AUTHORIZATION_CRES_FAILED_REPLY_FAILED;
+ return ANASTASIS_AUTHORIZATION_CRES_FAILED;
}
GNUNET_break (0 == fclose (f));
}
@@ -235,6 +233,8 @@ file_process (struct ANASTASIS_AUTHORIZATION_State *as,
"application/json"))
{
resp = TALER_MHD_MAKE_JSON_PACK (
+ GNUNET_JSON_pack_string ("challenge_type",
+ "FILE_WRITTEN"),
GNUNET_JSON_pack_string ("filename",
as->filename));
}
@@ -260,12 +260,12 @@ file_process (struct ANASTASIS_AUTHORIZATION_State *as,
MHD_RESULT mres;
mres = MHD_queue_response (connection,
- MHD_HTTP_FORBIDDEN,
+ MHD_HTTP_OK,
resp);
MHD_destroy_response (resp);
if (MHD_YES != mres)
- return ANASTASIS_AUTHORIZATION_RES_SUCCESS_REPLY_FAILED;
- return ANASTASIS_AUTHORIZATION_RES_SUCCESS;
+ return ANASTASIS_AUTHORIZATION_CRES_SUCCESS_REPLY_FAILED;
+ return ANASTASIS_AUTHORIZATION_CRES_SUCCESS;
}
}
}
@@ -304,7 +304,7 @@ libanastasis_plugin_authorization_file_init (void *cls)
plugin->code_retransmission_frequency = GNUNET_TIME_UNIT_MINUTES;
plugin->validate = &file_validate;
plugin->start = &file_start;
- plugin->process = &file_process;
+ plugin->challenge = &file_challenge;
plugin->cleanup = &file_cleanup;
return plugin;
}
diff --git a/src/authorization/anastasis_authorization_plugin_iban.c b/src/authorization/anastasis_authorization_plugin_iban.c
index 7717770..92b4565 100644
--- a/src/authorization/anastasis_authorization_plugin_iban.c
+++ b/src/authorization/anastasis_authorization_plugin_iban.c
@@ -3,7 +3,7 @@
Copyright (C) 2021 Anastasis SARL
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
+ terms of the GNU Affero 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
@@ -209,7 +209,7 @@ iban_validate (void *cls,
GNUNET_free (iban_number);
if (MHD_NO ==
TALER_MHD_reply_with_error (connection,
- MHD_HTTP_EXPECTATION_FAILED,
+ MHD_HTTP_CONFLICT,
TALER_EC_ANASTASIS_IBAN_INVALID,
emsg))
{
@@ -293,105 +293,13 @@ bank_event_cb (void *cls,
}
GNUNET_free (amount_s);
}
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "IBAN event triggers resumption of request handling\n");
MHD_resume_connection (as->connection);
as->trigger (as->trigger_cls);
}
-/**
- * Respond with instructions to the user how to
- * satisfy the challenge.
- *
- * @param as our state
- * @param connection connection to respond on
- * @return state of the request
- */
-static enum ANASTASIS_AUTHORIZATION_Result
-respond_with_challenge (struct ANASTASIS_AUTHORIZATION_State *as,
- struct MHD_Connection *connection)
-{
- struct IBAN_Context *ctx = as->ctx;
- const char *mime;
- const char *lang;
- MHD_RESULT mres;
-
- mime = MHD_lookup_connection_value (connection,
- MHD_HEADER_KIND,
- MHD_HTTP_HEADER_ACCEPT);
- if (NULL == mime)
- mime = "text/plain";
- lang = MHD_lookup_connection_value (connection,
- MHD_HEADER_KIND,
- MHD_HTTP_HEADER_ACCEPT_LANGUAGE);
- if (NULL == lang)
- lang = "en";
-
- /* Build HTTP response */
- {
- struct MHD_Response *resp;
-
- if (TALER_MHD_xmime_matches (mime,
- "application/json"))
- {
- char subject[64];
-
- GNUNET_snprintf (subject,
- sizeof (subject),
- "Anastasis %llu",
- (unsigned long long) as->code);
- resp = TALER_MHD_MAKE_JSON_PACK (
- GNUNET_JSON_pack_string ("method",
- "iban"),
- GNUNET_JSON_pack_bool ("async",
- true),
- GNUNET_JSON_pack_uint64 ("answer_code",
- as->code),
- GNUNET_JSON_pack_object_steal (
- "details",
- GNUNET_JSON_PACK (
- TALER_JSON_pack_amount ("challenge_amount",
- &ctx->expected_amount),
- GNUNET_JSON_pack_string ("credit_iban",
- ctx->business_iban),
- GNUNET_JSON_pack_string ("business_name",
- ctx->business_name),
- GNUNET_JSON_pack_string ("wire_transfer_subject",
- subject))));
- }
- else
- {
- size_t reply_len;
- char *reply;
-
- reply_len = GNUNET_asprintf (&reply,
- get_message (ctx->messages,
- connection,
- "instructions"),
- TALER_amount2s (&ctx->expected_amount),
- ctx->business_name,
- ctx->business_iban,
- (unsigned long long) as->code);
- resp = MHD_create_response_from_buffer (reply_len,
- reply,
- MHD_RESPMEM_MUST_COPY);
- GNUNET_free (reply);
- TALER_MHD_add_global_headers (resp);
- GNUNET_break (MHD_YES ==
- MHD_add_response_header (resp,
- MHD_HTTP_HEADER_CONTENT_TYPE,
- "text/plain"));
- }
- mres = MHD_queue_response (connection,
- MHD_HTTP_ACCEPTED,
- resp);
- MHD_destroy_response (resp);
- if (MHD_YES != mres)
- return ANASTASIS_AUTHORIZATION_RES_SUCCESS_REPLY_FAILED;
- return ANASTASIS_AUTHORIZATION_RES_SUCCESS;
- }
-}
-
-
#include "iban.c"
@@ -461,12 +369,14 @@ test_wire_transfers (struct ANASTASIS_AUTHORIZATION_State *as)
struct ANASTASIS_DatabasePlugin *db = ctx->ac->db;
enum GNUNET_DB_QueryStatus qs;
struct GNUNET_TIME_Absolute now;
- struct GNUNET_TIME_Absolute limit;
+ struct GNUNET_TIME_Timestamp limit;
now = GNUNET_TIME_absolute_get ();
- limit = GNUNET_TIME_absolute_subtract (now,
- CODE_VALIDITY_PERIOD);
- (void) GNUNET_TIME_round_abs (&limit);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Testing for wire transfers\n");
+ limit = GNUNET_TIME_absolute_to_timestamp (
+ GNUNET_TIME_absolute_subtract (now,
+ CODE_VALIDITY_PERIOD));
qs = db->test_auth_iban_payment (
db->cls,
as->iban_number,
@@ -482,15 +392,13 @@ test_wire_transfers (struct ANASTASIS_AUTHORIZATION_State *as)
MHD_HTTP_INTERNAL_SERVER_ERROR,
TALER_EC_GENERIC_DB_FETCH_FAILED,
NULL))
- ? WTS_FAILED_WITH_REPLY
- : WTS_FAILED_WITHOUT_REPLY;
+ ? WTS_FAILED_WITH_REPLY
+ : WTS_FAILED_WITHOUT_REPLY;
case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
return WTS_NOT_READY;
case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
break;
}
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Marking IBAN challenge as satisfied!\n");
qs = db->mark_challenge_code_satisfied (
db->cls,
&as->truth_uuid,
@@ -501,26 +409,124 @@ test_wire_transfers (struct ANASTASIS_AUTHORIZATION_State *as)
/**
+ * Respond with instructions to the user how to
+ * satisfy the challenge.
+ *
+ * @param as authorization state
+ * @param connection HTTP client request (for queuing response, such as redirection to video portal)
+ * @return state of the request
+ */
+static enum ANASTASIS_AUTHORIZATION_ChallengeResult
+iban_challenge (struct ANASTASIS_AUTHORIZATION_State *as,
+ struct MHD_Connection *connection)
+{
+ struct IBAN_Context *ctx = as->ctx;
+ const char *mime;
+ const char *lang;
+ MHD_RESULT mres;
+
+ mime = MHD_lookup_connection_value (connection,
+ MHD_HEADER_KIND,
+ MHD_HTTP_HEADER_ACCEPT);
+ if (NULL == mime)
+ mime = "text/plain";
+ lang = MHD_lookup_connection_value (connection,
+ MHD_HEADER_KIND,
+ MHD_HTTP_HEADER_ACCEPT_LANGUAGE);
+ if (NULL == lang)
+ lang = "en";
+
+ /* Build HTTP response */
+ {
+ struct MHD_Response *resp;
+
+ if (TALER_MHD_xmime_matches (mime,
+ "application/json"))
+ {
+ char subject[64];
+
+ GNUNET_snprintf (subject,
+ sizeof (subject),
+ "Anastasis %llu",
+ (unsigned long long) as->code);
+ resp = TALER_MHD_MAKE_JSON_PACK (
+ GNUNET_JSON_pack_string ("challenge_type",
+ "IBAN_WIRE"),
+ GNUNET_JSON_pack_object_steal (
+ "wire_details",
+ GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_uint64 (
+ "answer_code",
+ as->code),
+ TALER_JSON_pack_amount (
+ "challenge_amount",
+ &ctx->expected_amount),
+ GNUNET_JSON_pack_string (
+ "credit_iban",
+ ctx->business_iban),
+ GNUNET_JSON_pack_string (
+ "business_name",
+ ctx->business_name),
+ GNUNET_JSON_pack_string (
+ "wire_transfer_subject",
+ subject))));
+ }
+ else
+ {
+ size_t reply_len;
+ char *reply;
+
+ reply_len = GNUNET_asprintf (&reply,
+ get_message (ctx->messages,
+ connection,
+ "instructions"),
+ TALER_amount2s (&ctx->expected_amount),
+ ctx->business_name,
+ ctx->business_iban,
+ (unsigned long long) as->code);
+ resp = MHD_create_response_from_buffer (reply_len,
+ reply,
+ MHD_RESPMEM_MUST_COPY);
+ GNUNET_free (reply);
+ TALER_MHD_add_global_headers (resp);
+ GNUNET_break (MHD_YES ==
+ MHD_add_response_header (resp,
+ MHD_HTTP_HEADER_CONTENT_TYPE,
+ "text/plain"));
+ }
+ mres = MHD_queue_response (connection,
+ MHD_HTTP_OK,
+ resp);
+ MHD_destroy_response (resp);
+ if (MHD_YES != mres)
+ return ANASTASIS_AUTHORIZATION_CRES_SUCCESS_REPLY_FAILED;
+ return ANASTASIS_AUTHORIZATION_CRES_SUCCESS;
+ }
+}
+
+
+/**
* Begin issuing authentication challenge to user based on @a data.
* I.e. start to send IBAN or e-mail or launch video identification.
*
* @param as authorization state
* @param timeout how long do we have to produce a reply
+ * @param challenge_response hash of the challenge response, or NULL
* @param connection HTTP client request (for queuing response, such as redirection to video portal)
* @return state of the request
*/
-static enum ANASTASIS_AUTHORIZATION_Result
-iban_process (struct ANASTASIS_AUTHORIZATION_State *as,
- struct GNUNET_TIME_Absolute timeout,
- struct MHD_Connection *connection)
+static enum ANASTASIS_AUTHORIZATION_SolveResult
+iban_solve (struct ANASTASIS_AUTHORIZATION_State *as,
+ struct GNUNET_TIME_Absolute timeout,
+ const struct GNUNET_HashCode *challenge_response,
+ struct MHD_Connection *connection)
{
struct IBAN_Context *ctx = as->ctx;
struct ANASTASIS_DatabasePlugin *db = ctx->ac->db;
MHD_RESULT mres;
enum GNUNET_DB_QueryStatus qs;
- struct MHD_Response *resp;
struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
- struct GNUNET_TIME_Absolute after;
+ struct GNUNET_TIME_Timestamp after;
if (NULL == as->eh)
{
@@ -530,10 +536,6 @@ iban_process (struct ANASTASIS_AUTHORIZATION_State *as,
.code = GNUNET_htonll (as->code)
};
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Subscribing to events for code %llu from %s\n",
- (unsigned long long) as->code,
- as->iban_number);
GNUNET_CRYPTO_hash (as->iban_number,
strlen (as->iban_number),
&espec.debit_iban_hash);
@@ -544,9 +546,9 @@ iban_process (struct ANASTASIS_AUTHORIZATION_State *as,
&bank_event_cb,
as);
}
- after = GNUNET_TIME_absolute_subtract (now,
- CODE_VALIDITY_PERIOD);
- (void) GNUNET_TIME_round_abs (&after);
+ after = GNUNET_TIME_absolute_to_timestamp (
+ GNUNET_TIME_absolute_subtract (now,
+ CODE_VALIDITY_PERIOD));
qs = db->test_challenge_code_satisfied (db->cls,
&as->truth_uuid,
as->code,
@@ -555,45 +557,54 @@ iban_process (struct ANASTASIS_AUTHORIZATION_State *as,
{
case GNUNET_DB_STATUS_HARD_ERROR:
case GNUNET_DB_STATUS_SOFT_ERROR:
- resp = TALER_MHD_make_error (TALER_EC_GENERIC_DB_FETCH_FAILED,
- "test_challenge_code_satisfied");
- mres = MHD_queue_response (connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- resp);
- MHD_destroy_response (resp);
+ mres = TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_DB_FETCH_FAILED,
+ "test challenge code satisfied");
if (MHD_YES != mres)
- return ANASTASIS_AUTHORIZATION_RES_FAILED_REPLY_FAILED;
- return ANASTASIS_AUTHORIZATION_RES_FAILED;
+ return ANASTASIS_AUTHORIZATION_SRES_FAILED_REPLY_FAILED;
+ return ANASTASIS_AUTHORIZATION_SRES_FAILED;
case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
switch (test_wire_transfers (as))
{
case WTS_SUCCESS:
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"IBAN authorization finished!\n");
- return ANASTASIS_AUTHORIZATION_RES_FINISHED;
+ return ANASTASIS_AUTHORIZATION_SRES_FINISHED;
case WTS_NOT_READY:
break; /* continue below */
case WTS_FAILED_WITH_REPLY:
- return ANASTASIS_AUTHORIZATION_RES_FAILED;
+ return ANASTASIS_AUTHORIZATION_SRES_FAILED;
case WTS_FAILED_WITHOUT_REPLY:
- return ANASTASIS_AUTHORIZATION_RES_FAILED_REPLY_FAILED;
+ return ANASTASIS_AUTHORIZATION_SRES_FAILED_REPLY_FAILED;
}
if (GNUNET_TIME_absolute_is_future (timeout))
{
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Suspending IBAN check until %s\n",
+ GNUNET_TIME_absolute2s (timeout));
as->connection = connection;
MHD_suspend_connection (connection);
- return ANASTASIS_AUTHORIZATION_RES_SUSPENDED;
+ return ANASTASIS_AUTHORIZATION_SRES_SUSPENDED;
}
- return respond_with_challenge (as,
- connection);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Timeout reached at %s, failing request\n",
+ GNUNET_TIME_absolute2s (timeout));
+ mres = TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_FORBIDDEN,
+ TALER_EC_ANASTASIS_IBAN_MISSING_TRANSFER,
+ NULL);
+ if (MHD_YES != mres)
+ return ANASTASIS_AUTHORIZATION_SRES_FAILED_REPLY_FAILED;
+ return ANASTASIS_AUTHORIZATION_SRES_FAILED;
case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"IBAN authorization finished!\n");
- return ANASTASIS_AUTHORIZATION_RES_FINISHED;
+ return ANASTASIS_AUTHORIZATION_SRES_FINISHED;
}
/* should be impossible */
GNUNET_break (0);
- return ANASTASIS_AUTHORIZATION_RES_FAILED_REPLY_FAILED;
+ return ANASTASIS_AUTHORIZATION_SRES_FAILED_REPLY_FAILED;
}
@@ -708,9 +719,9 @@ libanastasis_plugin_authorization_iban_init (void *cls)
plugin->cls = ctx;
plugin->validate = &iban_validate;
plugin->start = &iban_start;
- plugin->process = &iban_process;
+ plugin->challenge = &iban_challenge;
+ plugin->solve = &iban_solve;
plugin->cleanup = &iban_cleanup;
-
return plugin;
}
diff --git a/src/authorization/anastasis_authorization_plugin_post.c b/src/authorization/anastasis_authorization_plugin_post.c
index 4adeffd..9410b58 100644
--- a/src/authorization/anastasis_authorization_plugin_post.c
+++ b/src/authorization/anastasis_authorization_plugin_post.c
@@ -3,7 +3,7 @@
Copyright (C) 2021 Anastasis SARL
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
+ terms of the GNU Affero 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
@@ -232,7 +232,7 @@ post_validate (void *cls,
{
if (MHD_NO ==
TALER_MHD_reply_with_error (connection,
- MHD_HTTP_EXPECTATION_FAILED,
+ MHD_HTTP_CONFLICT,
TALER_EC_ANASTASIS_POST_INVALID,
"JSON malformed"))
return GNUNET_SYSERR;
@@ -248,7 +248,7 @@ post_validate (void *cls,
json_decref (j);
if (MHD_NO ==
TALER_MHD_reply_with_error (connection,
- MHD_HTTP_EXPECTATION_FAILED,
+ MHD_HTTP_CONFLICT,
TALER_EC_ANASTASIS_POST_INVALID,
"JSON lacked required address information"))
return GNUNET_SYSERR;
@@ -334,8 +334,12 @@ post_done_cb (void *cls,
{
struct ANASTASIS_AUTHORIZATION_State *as = cls;
- as->child = NULL;
as->cwh = NULL;
+ if (NULL != as->child)
+ {
+ GNUNET_OS_process_destroy (as->child);
+ as->child = NULL;
+ }
as->pst = type;
as->exit_code = exit_code;
MHD_resume_connection (as->connection);
@@ -348,14 +352,12 @@ post_done_cb (void *cls,
* I.e. start to send SMS or e-mail or launch video identification.
*
* @param as authorization state
- * @param timeout how long do we have to produce a reply
* @param connection HTTP client request (for queuing response, such as redirection to video portal)
* @return state of the request
*/
-static enum ANASTASIS_AUTHORIZATION_Result
-post_process (struct ANASTASIS_AUTHORIZATION_State *as,
- struct GNUNET_TIME_Absolute timeout,
- struct MHD_Connection *connection)
+static enum ANASTASIS_AUTHORIZATION_ChallengeResult
+post_challenge (struct ANASTASIS_AUTHORIZATION_State *as,
+ struct MHD_Connection *connection)
{
const char *mime;
const char *lang;
@@ -379,7 +381,6 @@ post_process (struct ANASTASIS_AUTHORIZATION_State *as,
GNUNET_JSON_spec_end ()
};
- (void) timeout;
mime = MHD_lookup_connection_value (connection,
MHD_HEADER_KIND,
MHD_HTTP_HEADER_ACCEPT);
@@ -401,8 +402,8 @@ post_process (struct ANASTASIS_AUTHORIZATION_State *as,
TALER_EC_ANASTASIS_POST_INVALID,
"address information incomplete");
if (MHD_YES != mres)
- return ANASTASIS_AUTHORIZATION_RES_FAILED_REPLY_FAILED;
- return ANASTASIS_AUTHORIZATION_RES_FAILED;
+ return ANASTASIS_AUTHORIZATION_CRES_FAILED_REPLY_FAILED;
+ return ANASTASIS_AUTHORIZATION_CRES_FAILED;
}
if (NULL == as->msg)
{
@@ -418,8 +419,8 @@ post_process (struct ANASTASIS_AUTHORIZATION_State *as,
TALER_EC_ANASTASIS_POST_HELPER_EXEC_FAILED,
"pipe");
if (MHD_YES != mres)
- return ANASTASIS_AUTHORIZATION_RES_FAILED_REPLY_FAILED;
- return ANASTASIS_AUTHORIZATION_RES_FAILED;
+ return ANASTASIS_AUTHORIZATION_CRES_FAILED_REPLY_FAILED;
+ return ANASTASIS_AUTHORIZATION_CRES_FAILED;
}
as->child = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_ERR,
p,
@@ -441,28 +442,19 @@ post_process (struct ANASTASIS_AUTHORIZATION_State *as,
TALER_EC_ANASTASIS_POST_HELPER_EXEC_FAILED,
"exec");
if (MHD_YES != mres)
- return ANASTASIS_AUTHORIZATION_RES_FAILED_REPLY_FAILED;
- return ANASTASIS_AUTHORIZATION_RES_FAILED;
+ return ANASTASIS_AUTHORIZATION_CRES_FAILED_REPLY_FAILED;
+ return ANASTASIS_AUTHORIZATION_CRES_FAILED;
}
pipe_stdin = GNUNET_DISK_pipe_detach_end (p,
GNUNET_DISK_PIPE_END_WRITE);
GNUNET_assert (NULL != pipe_stdin);
GNUNET_DISK_pipe_close (p);
- {
- char *tpk;
-
- tpk = GNUNET_STRINGS_data_to_string_alloc (
- &as->truth_uuid,
- sizeof (as->truth_uuid));
- GNUNET_asprintf (&as->msg,
- get_message (as->ctx->messages,
- connection,
- "body"),
- (unsigned long long) as->code,
- tpk);
- GNUNET_free (tpk);
- }
-
+ GNUNET_asprintf (&as->msg,
+ get_message (as->ctx->messages,
+ connection,
+ "body"),
+ ANASTASIS_pin2s (as->code),
+ ANASTASIS_CRYPTO_uuid2s (&as->truth_uuid));
{
const char *off = as->msg;
size_t left = strlen (off);
@@ -483,8 +475,8 @@ post_process (struct ANASTASIS_AUTHORIZATION_State *as,
TALER_EC_ANASTASIS_POST_HELPER_EXEC_FAILED,
"write");
if (MHD_YES != mres)
- return ANASTASIS_AUTHORIZATION_RES_FAILED_REPLY_FAILED;
- return ANASTASIS_AUTHORIZATION_RES_FAILED;
+ return ANASTASIS_AUTHORIZATION_CRES_FAILED_REPLY_FAILED;
+ return ANASTASIS_AUTHORIZATION_CRES_FAILED;
}
as->msg_off += ret;
off += ret;
@@ -497,14 +489,14 @@ post_process (struct ANASTASIS_AUTHORIZATION_State *as,
as);
as->connection = connection;
MHD_suspend_connection (connection);
- return ANASTASIS_AUTHORIZATION_RES_SUSPENDED;
+ return ANASTASIS_AUTHORIZATION_CRES_SUSPENDED;
}
if (NULL != as->cwh)
{
/* Spurious call, why are we here? */
GNUNET_break (0);
MHD_suspend_connection (connection);
- return ANASTASIS_AUTHORIZATION_RES_SUSPENDED;
+ return ANASTASIS_AUTHORIZATION_CRES_SUSPENDED;
}
if ( (GNUNET_OS_PROCESS_EXITED != as->pst) ||
(0 != as->exit_code) )
@@ -521,8 +513,8 @@ post_process (struct ANASTASIS_AUTHORIZATION_State *as,
TALER_EC_ANASTASIS_POST_HELPER_COMMAND_FAILED,
es);
if (MHD_YES != mres)
- return ANASTASIS_AUTHORIZATION_RES_FAILED_REPLY_FAILED;
- return ANASTASIS_AUTHORIZATION_RES_FAILED;
+ return ANASTASIS_AUTHORIZATION_CRES_FAILED_REPLY_FAILED;
+ return ANASTASIS_AUTHORIZATION_CRES_FAILED;
}
/* Build HTTP response */
@@ -533,12 +525,9 @@ post_process (struct ANASTASIS_AUTHORIZATION_State *as,
"application/json"))
{
resp = TALER_MHD_MAKE_JSON_PACK (
- GNUNET_JSON_pack_uint64 ("code",
- TALER_EC_ANASTASIS_TRUTH_CHALLENGE_RESPONSE_REQUIRED),
- GNUNET_JSON_pack_string ("hint",
- TALER_ErrorCode_get_hint (
- TALER_EC_ANASTASIS_TRUTH_CHALLENGE_RESPONSE_REQUIRED)),
- GNUNET_JSON_pack_string ("detail",
+ GNUNET_JSON_pack_string ("challenge_type",
+ "TAN_SENT"),
+ GNUNET_JSON_pack_string ("tan_address_hint",
zip));
}
else
@@ -558,12 +547,12 @@ post_process (struct ANASTASIS_AUTHORIZATION_State *as,
TALER_MHD_add_global_headers (resp);
}
mres = MHD_queue_response (connection,
- MHD_HTTP_FORBIDDEN,
+ MHD_HTTP_OK,
resp);
MHD_destroy_response (resp);
if (MHD_YES != mres)
- return ANASTASIS_AUTHORIZATION_RES_SUCCESS_REPLY_FAILED;
- return ANASTASIS_AUTHORIZATION_RES_SUCCESS;
+ return ANASTASIS_AUTHORIZATION_CRES_SUCCESS_REPLY_FAILED;
+ return ANASTASIS_AUTHORIZATION_CRES_SUCCESS;
}
}
@@ -648,7 +637,7 @@ libanastasis_plugin_authorization_post_init (void *cls)
plugin->cls = ctx;
plugin->validate = &post_validate;
plugin->start = &post_start;
- plugin->process = &post_process;
+ plugin->challenge = &post_challenge;
plugin->cleanup = &post_cleanup;
if (GNUNET_OK !=
diff --git a/src/authorization/anastasis_authorization_plugin_sms.c b/src/authorization/anastasis_authorization_plugin_sms.c
index 94b2c0d..695e5d8 100644
--- a/src/authorization/anastasis_authorization_plugin_sms.c
+++ b/src/authorization/anastasis_authorization_plugin_sms.c
@@ -3,7 +3,7 @@
Copyright (C) 2019, 2021 Anastasis SARL
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
+ terms of the GNU Affero 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
@@ -219,7 +219,7 @@ sms_validate (void *cls,
{
if (MHD_NO ==
TALER_MHD_reply_with_error (connection,
- MHD_HTTP_EXPECTATION_FAILED,
+ MHD_HTTP_CONFLICT,
TALER_EC_ANASTASIS_SMS_PHONE_INVALID,
NULL))
return GNUNET_SYSERR;
@@ -295,8 +295,12 @@ sms_done_cb (void *cls,
{
struct ANASTASIS_AUTHORIZATION_State *as = cls;
- as->child = NULL;
as->cwh = NULL;
+ if (NULL != as->child)
+ {
+ GNUNET_OS_process_destroy (as->child);
+ as->child = NULL;
+ }
as->pst = type;
as->exit_code = exit_code;
MHD_resume_connection (as->connection);
@@ -309,20 +313,17 @@ sms_done_cb (void *cls,
* I.e. start to send SMS or e-mail or launch video identification.
*
* @param as authorization state
- * @param timeout how long do we have to produce a reply
* @param connection HTTP client request (for queuing response, such as redirection to video portal)
* @return state of the request
*/
-static enum ANASTASIS_AUTHORIZATION_Result
-sms_process (struct ANASTASIS_AUTHORIZATION_State *as,
- struct GNUNET_TIME_Absolute timeout,
- struct MHD_Connection *connection)
+static enum ANASTASIS_AUTHORIZATION_ChallengeResult
+sms_challenge (struct ANASTASIS_AUTHORIZATION_State *as,
+ struct MHD_Connection *connection)
{
MHD_RESULT mres;
const char *mime;
const char *lang;
- (void) timeout;
mime = MHD_lookup_connection_value (connection,
MHD_HEADER_KIND,
MHD_HTTP_HEADER_ACCEPT);
@@ -347,8 +348,8 @@ sms_process (struct ANASTASIS_AUTHORIZATION_State *as,
TALER_EC_ANASTASIS_SMS_HELPER_EXEC_FAILED,
"pipe");
if (MHD_YES != mres)
- return ANASTASIS_AUTHORIZATION_RES_FAILED_REPLY_FAILED;
- return ANASTASIS_AUTHORIZATION_RES_FAILED;
+ return ANASTASIS_AUTHORIZATION_CRES_FAILED_REPLY_FAILED;
+ return ANASTASIS_AUTHORIZATION_CRES_FAILED;
}
as->child = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_ERR,
p,
@@ -366,26 +367,17 @@ sms_process (struct ANASTASIS_AUTHORIZATION_State *as,
TALER_EC_ANASTASIS_SMS_HELPER_EXEC_FAILED,
"exec");
if (MHD_YES != mres)
- return ANASTASIS_AUTHORIZATION_RES_FAILED_REPLY_FAILED;
- return ANASTASIS_AUTHORIZATION_RES_FAILED;
+ return ANASTASIS_AUTHORIZATION_CRES_FAILED_REPLY_FAILED;
+ return ANASTASIS_AUTHORIZATION_CRES_FAILED;
}
pipe_stdin = GNUNET_DISK_pipe_detach_end (p,
GNUNET_DISK_PIPE_END_WRITE);
GNUNET_assert (NULL != pipe_stdin);
GNUNET_DISK_pipe_close (p);
- {
- char *tpk;
-
- tpk = GNUNET_STRINGS_data_to_string_alloc (
- &as->truth_uuid,
- sizeof (as->truth_uuid));
- GNUNET_asprintf (&as->msg,
- "A-%llu\nAnastasis\n%s",
- (unsigned long long) as->code,
- tpk);
- GNUNET_free (tpk);
- }
-
+ GNUNET_asprintf (&as->msg,
+ "%s\nAnastasis:\n%s",
+ ANASTASIS_pin2s (as->code),
+ ANASTASIS_CRYPTO_uuid2s (&as->truth_uuid));
{
const char *off = as->msg;
size_t left = strlen (off);
@@ -406,8 +398,8 @@ sms_process (struct ANASTASIS_AUTHORIZATION_State *as,
TALER_EC_ANASTASIS_SMS_HELPER_EXEC_FAILED,
"write");
if (MHD_YES != mres)
- return ANASTASIS_AUTHORIZATION_RES_FAILED_REPLY_FAILED;
- return ANASTASIS_AUTHORIZATION_RES_FAILED;
+ return ANASTASIS_AUTHORIZATION_CRES_FAILED_REPLY_FAILED;
+ return ANASTASIS_AUTHORIZATION_CRES_FAILED;
}
as->msg_off += ret;
off += ret;
@@ -420,14 +412,14 @@ sms_process (struct ANASTASIS_AUTHORIZATION_State *as,
as);
as->connection = connection;
MHD_suspend_connection (connection);
- return ANASTASIS_AUTHORIZATION_RES_SUSPENDED;
+ return ANASTASIS_AUTHORIZATION_CRES_SUSPENDED;
}
if (NULL != as->cwh)
{
/* Spurious call, why are we here? */
GNUNET_break (0);
MHD_suspend_connection (connection);
- return ANASTASIS_AUTHORIZATION_RES_SUSPENDED;
+ return ANASTASIS_AUTHORIZATION_CRES_SUSPENDED;
}
if ( (GNUNET_OS_PROCESS_EXITED != as->pst) ||
(0 != as->exit_code) )
@@ -444,8 +436,8 @@ sms_process (struct ANASTASIS_AUTHORIZATION_State *as,
TALER_EC_ANASTASIS_SMS_HELPER_COMMAND_FAILED,
es);
if (MHD_YES != mres)
- return ANASTASIS_AUTHORIZATION_RES_FAILED_REPLY_FAILED;
- return ANASTASIS_AUTHORIZATION_RES_FAILED;
+ return ANASTASIS_AUTHORIZATION_CRES_FAILED_REPLY_FAILED;
+ return ANASTASIS_AUTHORIZATION_CRES_FAILED;
}
/* Build HTTP response */
@@ -464,12 +456,9 @@ sms_process (struct ANASTASIS_AUTHORIZATION_State *as,
"application/json"))
{
resp = TALER_MHD_MAKE_JSON_PACK (
- GNUNET_JSON_pack_uint64 ("code",
- TALER_EC_ANASTASIS_TRUTH_CHALLENGE_RESPONSE_REQUIRED),
- GNUNET_JSON_pack_string ("hint",
- TALER_ErrorCode_get_hint (
- TALER_EC_ANASTASIS_TRUTH_CHALLENGE_RESPONSE_REQUIRED)),
- GNUNET_JSON_pack_string ("detail",
+ GNUNET_JSON_pack_string ("challenge_type",
+ "TAN_SENT"),
+ GNUNET_JSON_pack_string ("tan_address_hint",
end));
}
else
@@ -493,12 +482,12 @@ sms_process (struct ANASTASIS_AUTHORIZATION_State *as,
"text/plain"));
}
mres = MHD_queue_response (connection,
- MHD_HTTP_FORBIDDEN,
+ MHD_HTTP_OK,
resp);
MHD_destroy_response (resp);
if (MHD_YES != mres)
- return ANASTASIS_AUTHORIZATION_RES_SUCCESS_REPLY_FAILED;
- return ANASTASIS_AUTHORIZATION_RES_SUCCESS;
+ return ANASTASIS_AUTHORIZATION_CRES_SUCCESS_REPLY_FAILED;
+ return ANASTASIS_AUTHORIZATION_CRES_SUCCESS;
}
}
@@ -596,7 +585,7 @@ libanastasis_plugin_authorization_sms_init (void *cls)
plugin->cls = ctx;
plugin->validate = &sms_validate;
plugin->start = &sms_start;
- plugin->process = &sms_process;
+ plugin->challenge = &sms_challenge;
plugin->cleanup = &sms_cleanup;
if (GNUNET_OK !=
diff --git a/src/authorization/anastasis_authorization_plugin_totp.c b/src/authorization/anastasis_authorization_plugin_totp.c
new file mode 100644
index 0000000..c127e38
--- /dev/null
+++ b/src/authorization/anastasis_authorization_plugin_totp.c
@@ -0,0 +1,381 @@
+/*
+ This totp is part of Anastasis
+ Copyright (C) 2021 Anastasis SARL
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ terms of the GNU Affero 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ Anastasis; see the totp COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @totp anastasis_authorization_plugin_totp.c
+ * @brief authorization plugin using totp
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "anastasis_authorization_plugin.h"
+#include <taler/taler_mhd_lib.h>
+#include <gnunet/gnunet_db_lib.h>
+#include "anastasis_database_lib.h"
+#include <gcrypt.h>
+
+
+/**
+ * How many retries do we allow per code?
+ */
+#define INITIAL_RETRY_COUNTER 3
+
+/**
+ * How long is a TOTP code valid?
+ */
+#define TOTP_VALIDITY_PERIOD GNUNET_TIME_relative_multiply ( \
+ GNUNET_TIME_UNIT_SECONDS, 30)
+
+/**
+ * Range of time we allow (plus-minus).
+ */
+#define TIME_INTERVAL_RANGE 2
+
+/**
+ * How long is the shared secret in bytes?
+ */
+#define SECRET_LEN 32
+
+
+/**
+ * Saves the state of a authorization process
+ */
+struct ANASTASIS_AUTHORIZATION_State
+{
+ /**
+ * UUID of the challenge which is authorised
+ */
+ struct ANASTASIS_CRYPTO_TruthUUIDP truth_uuid;
+
+ /**
+ * Was the challenge satisfied?
+ */
+ struct GNUNET_HashCode valid_replies[TIME_INTERVAL_RANGE * 2 + 1];
+
+ /**
+ * Our context.
+ */
+ const struct ANASTASIS_AuthorizationContext *ac;
+
+};
+
+
+/**
+ * Validate @a data is a well-formed input into the challenge method,
+ * i.e. @a data is a well-formed phone number for sending an SMS, or
+ * a well-formed e-mail address for sending an e-mail. Not expected to
+ * check that the phone number or e-mail account actually exists.
+ *
+ * To be possibly used before issuing a 402 payment required to the client.
+ *
+ * @param cls closure with a `const struct ANASTASIS_AuthorizationContext *`
+ * @param connection HTTP client request (for queuing response)
+ * @param truth_mime mime type of @e data
+ * @param data input to validate (i.e. is it a valid phone number, etc.)
+ * @param data_length number of bytes in @a data
+ * @return #GNUNET_OK if @a data is valid,
+ * #GNUNET_NO if @a data is invalid and a reply was successfully queued on @a connection
+ * #GNUNET_SYSERR if @a data invalid but we failed to queue a reply on @a connection
+ */
+static enum GNUNET_GenericReturnValue
+totp_validate (void *cls,
+ struct MHD_Connection *connection,
+ const char *truth_mime,
+ const char *data,
+ size_t data_length)
+{
+ (void) cls;
+ (void) truth_mime;
+ (void) connection;
+ if (NULL == data)
+ {
+ GNUNET_break_op (0);
+ if (MHD_NO ==
+ TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_CONFLICT,
+ TALER_EC_ANASTASIS_TOTP_KEY_MISSING,
+ NULL))
+ return GNUNET_SYSERR;
+ return GNUNET_NO;
+ }
+ if (SECRET_LEN != data_length)
+ {
+ GNUNET_break_op (0);
+ if (MHD_NO ==
+ TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_CONFLICT,
+ TALER_EC_ANASTASIS_TOTP_KEY_INVALID,
+ NULL))
+ return GNUNET_SYSERR;
+ return GNUNET_NO;
+ }
+ return GNUNET_OK;
+}
+
+
+/**
+ * Compute TOTP code at current time with offset
+ * @a time_off for the @a key.
+ *
+ * @param time_off offset to apply when computing the code
+ * @param key input key material
+ * @param key_size number of bytes in @a key
+ * @return TOTP code at this time
+ */
+static uint64_t
+compute_totp (int time_off,
+ const void *key,
+ size_t key_size)
+{
+ struct GNUNET_TIME_Absolute now;
+ time_t t;
+ uint64_t ctr;
+ uint8_t hmac[20]; /* SHA1: 20 bytes */
+
+ now = GNUNET_TIME_absolute_get ();
+ while (time_off < 0)
+ {
+ now = GNUNET_TIME_absolute_subtract (now,
+ TOTP_VALIDITY_PERIOD);
+ time_off++;
+ }
+ while (time_off > 0)
+ {
+ now = GNUNET_TIME_absolute_add (now,
+ TOTP_VALIDITY_PERIOD);
+ time_off--;
+ }
+ t = now.abs_value_us / GNUNET_TIME_UNIT_SECONDS.rel_value_us;
+ ctr = GNUNET_htonll (t / 30LLU);
+
+ {
+ gcry_md_hd_t md;
+ const unsigned char *mc;
+
+ GNUNET_assert (GPG_ERR_NO_ERROR ==
+ gcry_md_open (&md,
+ GCRY_MD_SHA1,
+ GCRY_MD_FLAG_HMAC));
+ gcry_md_setkey (md,
+ key,
+ key_size);
+ gcry_md_write (md,
+ &ctr,
+ sizeof (ctr));
+ mc = gcry_md_read (md,
+ GCRY_MD_SHA1);
+ GNUNET_assert (NULL != mc);
+ memcpy (hmac,
+ mc,
+ sizeof (hmac));
+ gcry_md_close (md);
+ }
+
+ {
+ uint32_t code = 0;
+ int offset;
+
+ offset = hmac[sizeof (hmac) - 1] & 0x0f;
+ for (int count = 0; count < 4; count++)
+ code |= ((uint32_t) hmac[offset + 3 - count]) << (8 * count);
+ code &= 0x7fffffff;
+ /* always use 8 digits (maximum) */
+ code = code % 100000000;
+ return code;
+ }
+}
+
+
+/**
+ * Begin issuing authentication challenge to user based on @a data.
+ *
+ * @param cls closure
+ * @param trigger function to call when we made progress
+ * @param trigger_cls closure for @a trigger
+ * @param truth_uuid Identifier of the challenge, to be (if possible) included in the
+ * interaction with the user
+ * @param code always 0 (direct validation, backend does
+ * not generate a code in this mode)
+ * @param data truth for input to validate (i.e. the shared secret)
+ * @param data_length number of bytes in @a data
+ * @return state to track progress on the authorization operation, NULL on failure
+ */
+static struct ANASTASIS_AUTHORIZATION_State *
+totp_start (void *cls,
+ GNUNET_SCHEDULER_TaskCallback trigger,
+ void *trigger_cls,
+ const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid,
+ uint64_t code,
+ const void *data,
+ size_t data_length)
+{
+ const struct ANASTASIS_AuthorizationContext *ac = cls;
+ struct ANASTASIS_AUTHORIZATION_State *as;
+ uint64_t want;
+ unsigned int off = 0;
+
+ GNUNET_assert (0 == code);
+ as = GNUNET_new (struct ANASTASIS_AUTHORIZATION_State);
+ as->ac = ac;
+ as->truth_uuid = *truth_uuid;
+ for (int i = -TIME_INTERVAL_RANGE;
+ i <= TIME_INTERVAL_RANGE;
+ i++)
+ {
+ want = compute_totp (i,
+ data,
+ data_length);
+ ANASTASIS_hash_answer (want,
+ &as->valid_replies[off++]);
+ }
+ return as;
+}
+
+
+/**
+ * Check authentication response from the user.
+ *
+ * @param as authorization state
+ * @param timeout how long do we have to produce a reply
+ * @param challenge_response hash of the response
+ * @param connection HTTP client request (for queuing response, such as redirection to video portal)
+ * @return state of the request
+ */
+static enum ANASTASIS_AUTHORIZATION_SolveResult
+totp_solve (struct ANASTASIS_AUTHORIZATION_State *as,
+ struct GNUNET_TIME_Absolute timeout,
+ const struct GNUNET_HashCode *challenge_response,
+ struct MHD_Connection *connection)
+{
+ MHD_RESULT mres;
+ const char *mime;
+ const char *lang;
+
+ for (unsigned int i = 0; i<=TIME_INTERVAL_RANGE * 2; i++)
+ if (0 ==
+ GNUNET_memcmp (challenge_response,
+ &as->valid_replies[i]))
+ return ANASTASIS_AUTHORIZATION_SRES_FINISHED;
+ mime = MHD_lookup_connection_value (connection,
+ MHD_HEADER_KIND,
+ MHD_HTTP_HEADER_ACCEPT);
+ if (NULL == mime)
+ mime = "text/plain";
+ lang = MHD_lookup_connection_value (connection,
+ MHD_HEADER_KIND,
+ MHD_HTTP_HEADER_ACCEPT_LANGUAGE);
+ if (NULL == lang)
+ lang = "en";
+
+ /* Build HTTP response */
+ {
+ struct MHD_Response *resp;
+ struct GNUNET_TIME_Timestamp now;
+
+ now = GNUNET_TIME_timestamp_get ();
+ if (TALER_MHD_xmime_matches (mime,
+ "application/json"))
+ {
+ resp = TALER_MHD_MAKE_JSON_PACK (
+ GNUNET_JSON_pack_uint64 ("code",
+ TALER_EC_ANASTASIS_TRUTH_CHALLENGE_FAILED),
+ GNUNET_JSON_pack_string ("hint",
+ TALER_ErrorCode_get_hint (
+ TALER_EC_ANASTASIS_TRUTH_CHALLENGE_FAILED)),
+ GNUNET_JSON_pack_timestamp ("server_time",
+ now));
+ }
+ else
+ {
+ size_t response_size;
+ char *response;
+
+ // FIXME: i18n of the message based on 'lang' ...
+ response_size
+ = GNUNET_asprintf (&response,
+ "Server time: %s",
+ GNUNET_TIME_timestamp2s (now));
+ resp = MHD_create_response_from_buffer (response_size,
+ response,
+ MHD_RESPMEM_MUST_COPY);
+ TALER_MHD_add_global_headers (resp);
+ GNUNET_break (MHD_YES ==
+ MHD_add_response_header (resp,
+ MHD_HTTP_HEADER_CONTENT_TYPE,
+ "text/plain"));
+ }
+ mres = MHD_queue_response (connection,
+ MHD_HTTP_FORBIDDEN,
+ resp);
+ MHD_destroy_response (resp);
+ }
+ if (MHD_YES != mres)
+ return ANASTASIS_AUTHORIZATION_SRES_FAILED_REPLY_FAILED;
+ return ANASTASIS_AUTHORIZATION_SRES_FAILED;
+}
+
+
+/**
+ * Free internal state associated with @a as.
+ *
+ * @param as state to clean up
+ */
+static void
+totp_cleanup (struct ANASTASIS_AUTHORIZATION_State *as)
+{
+ GNUNET_free (as);
+}
+
+
+/**
+ * Initialize Totp based authorization plugin
+ *
+ * @param cls a configuration instance
+ * @return NULL on error, otherwise a `struct ANASTASIS_AuthorizationPlugin`
+ */
+void *
+libanastasis_plugin_authorization_totp_init (void *cls)
+{
+ const struct ANASTASIS_AuthorizationContext *ac = cls;
+ struct ANASTASIS_AuthorizationPlugin *plugin;
+
+ plugin = GNUNET_new (struct ANASTASIS_AuthorizationPlugin);
+ plugin->cls = (void *) ac;
+ plugin->user_provided_code = true;
+ plugin->retry_counter = INITIAL_RETRY_COUNTER;
+ plugin->code_validity_period = TOTP_VALIDITY_PERIOD;
+ plugin->code_rotation_period = plugin->code_validity_period;
+ plugin->code_retransmission_frequency = plugin->code_validity_period;
+ plugin->validate = &totp_validate;
+ plugin->start = &totp_start;
+ plugin->solve = &totp_solve;
+ plugin->cleanup = &totp_cleanup;
+ return plugin;
+}
+
+
+/**
+ * Unload authorization plugin
+ *
+ * @param cls a `struct ANASTASIS_AuthorizationPlugin`
+ * @return NULL (always)
+ */
+void *
+libanastasis_plugin_authorization_totp_done (void *cls)
+{
+ struct ANASTASIS_AuthorizationPlugin *plugin = cls;
+
+ GNUNET_free (plugin);
+ return NULL;
+}
diff --git a/src/authorization/authorization-email-messages.json b/src/authorization/authorization-email-messages.json
index 5a2e048..5e4ddb3 100644
--- a/src/authorization/authorization-email-messages.json
+++ b/src/authorization/authorization-email-messages.json
@@ -3,8 +3,8 @@
"instructions_i18n" : {
"de_DE" : "Ein Authorisierungscode wurde an %.*s@DOMAIN geschickt"
},
- "body" : "Your Anastasis recovery code is:\nA-%llu\n\nThis is for challenge %s.\n",
+ "body" : "Your Anastasis recovery code is:\n%s\n\nThis is for challenge %s.\n",
"body_i18n" : {
- "de_DE" : "Ihr Anastasis Autorisierungscode ist:\nA-%llu\n\nDies ist der Code für den Vorgang %s.\n"
+ "de_DE" : "Ihr Anastasis Autorisierungscode ist:\n%s\n\nDies ist der Code für den Vorgang %s.\n"
}
}
diff --git a/src/authorization/authorization-post-messages.json b/src/authorization/authorization-post-messages.json
index d2ac83a..c48c8ab 100644
--- a/src/authorization/authorization-post-messages.json
+++ b/src/authorization/authorization-post-messages.json
@@ -3,5 +3,5 @@
"instructions_i18n" : {
"de_DE" : "Ein Authorisierungscode wurde an eine Addresse mit der Postleitzahl %s geschickt"
},
- "body" : "Dear Customer\n\nThe Anastasis recovery code you need to\nrecover your data is A-%llu.\nThis is for challenge %s.\n\nBest regards\n\nYour Anastasis provider"
+ "body" : "Dear Customer\n\nThe Anastasis recovery code you need to\nrecover your data is %s.\nThis is for challenge %s.\n\nBest regards\n\nYour Anastasis provider"
}
diff --git a/src/authorization/iban.h b/src/authorization/iban.h
index 70db7ea..17836f4 100644
--- a/src/authorization/iban.h
+++ b/src/authorization/iban.h
@@ -3,7 +3,7 @@
Copyright (C) 2021 Anastasis SARL
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
+ terms of the GNU Affero 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
diff --git a/src/authorization/libanastasiseufin/lae_common.h b/src/authorization/libanastasiseufin/lae_common.h
index 8879ba3..1c2c8fd 100644
--- a/src/authorization/libanastasiseufin/lae_common.h
+++ b/src/authorization/libanastasiseufin/lae_common.h
@@ -36,7 +36,7 @@
* @param auth authentication data to use
* @return #GNUNET_OK in success
*/
-int
+enum GNUNET_GenericReturnValue
ANASTASIS_EUFIN_setup_auth_ (
CURL *easy,
const struct ANASTASIS_EUFIN_AuthenticationData *auth);
diff --git a/src/authorization/libanastasiseufin/lae_credit.c b/src/authorization/libanastasiseufin/lae_credit.c
index e8cabb5..dd6687b 100644
--- a/src/authorization/libanastasiseufin/lae_credit.c
+++ b/src/authorization/libanastasiseufin/lae_credit.c
@@ -65,7 +65,7 @@ struct ANASTASIS_EUFIN_CreditHistoryHandle
* were set,
* #GNUNET_SYSERR if there was a protocol violation in @a history
*/
-static int
+static enum GNUNET_GenericReturnValue
parse_account_history (struct ANASTASIS_EUFIN_CreditHistoryHandle *hh,
const json_t *history)
{
@@ -82,15 +82,15 @@ parse_account_history (struct ANASTASIS_EUFIN_CreditHistoryHandle *hh,
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
- for (unsigned int i = 0; i<json_array_size (history_array); i++)
+ for (size_t i = 0; i<json_array_size (history_array); i++)
{
struct ANASTASIS_EUFIN_CreditDetails td;
uint64_t row_id;
struct GNUNET_JSON_Specification hist_spec[] = {
TALER_JSON_spec_amount_any ("amount",
&td.amount),
- TALER_JSON_spec_absolute_time ("date",
- &td.execution_date),
+ GNUNET_JSON_spec_timestamp ("date",
+ &td.execution_date),
GNUNET_JSON_spec_uint64 ("row_id",
&row_id),
GNUNET_JSON_spec_string ("subject",
diff --git a/src/authorization/test-post.sh b/src/authorization/test-post.sh
new file mode 100755
index 0000000..fd3a8d8
--- /dev/null
+++ b/src/authorization/test-post.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+# This file is in the public domain.
+set -eu
+ADDR=`jq -n '{
+ full_name: "John Doe",
+ street: "Bar street 3",
+ city: "Wuppertal",
+ postcode: 42289,
+ country: "DE",
+ }'`
+
+echo "Your recovery code is 1234" | ./anastasis-authorization-post.sh "$ADDR"