diff options
author | BOSS_Marco <bossm8@students.bfh.ch> | 2019-10-30 15:35:06 +0100 |
---|---|---|
committer | BOSS_Marco <bossm8@students.bfh.ch> | 2019-10-30 15:35:06 +0100 |
commit | 895f886cbe84c1b3cf1aa7583f30913e9ee052c4 (patch) | |
tree | 75aa5b955153dccbf73d888a8cbc5f682e2dac8d | |
download | taler-mdb-895f886cbe84c1b3cf1aa7583f30913e9ee052c4.tar.gz taler-mdb-895f886cbe84c1b3cf1aa7583f30913e9ee052c4.tar.bz2 taler-mdb-895f886cbe84c1b3cf1aa7583f30913e9ee052c4.zip |
initial commit
-rw-r--r-- | .gitignore | 12 | ||||
-rw-r--r-- | README | 31 | ||||
-rw-r--r-- | doc/.gitkeep | 0 | ||||
-rw-r--r-- | src/configuration.h | 54 | ||||
-rw-r--r-- | src/main.c | 166 | ||||
-rw-r--r-- | src/makefile | 78 | ||||
-rw-r--r-- | src/mdb/.gitkeep | 0 | ||||
-rw-r--r-- | src/nfc-wallet/nfc.c | 118 | ||||
-rw-r--r-- | src/nfc-wallet/nfc.h | 34 | ||||
-rw-r--r-- | src/nfc-wallet/wallet.c | 124 | ||||
-rw-r--r-- | src/nfc-wallet/wallet.h | 57 | ||||
-rw-r--r-- | src/taler-processing/communication.c | 220 | ||||
-rw-r--r-- | src/taler-processing/communication.h | 51 | ||||
-rw-r--r-- | src/taler-processing/product.c | 126 | ||||
-rw-r--r-- | src/taler-processing/product.h | 67 | ||||
-rw-r--r-- | src/target.mk | 6 |
16 files changed, 1144 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a43af72 --- /dev/null +++ b/.gitignore @@ -0,0 +1,12 @@ +#ignore .pro fils +*.pro* + +#ignore object files +*.o + +#ignore build folder and binary files +build +taler-mdb + +#ignore qmake files +.qmake* @@ -0,0 +1,31 @@ +# Project : GNUTaler snack machine + +#### Author(s) + * BOSS Marco + * HOFER Dominik + +#### Prerequisite + * GNU gcc tool-chain + * C standard libraries + * libnfc + * libcurl + * pthread + * Gnu make + +#### Tested on + * Ubuntu LTS (18.04) + +#### Description + This is a app to run a snack machine as taler merchant with nfc payment interface. + +#### Tasks + * Add libjansson to parse and create json objects + * Build system, makefile provided is not suitable + +#### Remarks + * When using an ACR122 device there may be problems with libnfc, see libnfc for further information + +#### Noticeable points + * Taler wallet does not receive a second message when the payment was aborted, the wallet + has to be started again to receive a message via nfc + * Wallet does not show succes url string diff --git a/doc/.gitkeep b/doc/.gitkeep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/doc/.gitkeep diff --git a/src/configuration.h b/src/configuration.h new file mode 100644 index 0000000..354e99e --- /dev/null +++ b/src/configuration.h @@ -0,0 +1,54 @@ +/* + This file is part of TALER + Copyright (C) 2019 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more +details. + + You should have received a copy of the GNU General Public License +along with + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ + +/** +* @file configuration.h +* @brief in this file you can set your url specifications needed to comminicate with taler +* @author BOSS Marco +*/ + +#ifndef URL_H +#define URL_H + +static const char* const ORDER = "/order"; +static const char* const CHECK = "/check-payment"; +static const char* const ORDER_CHECK = "?order_id="; + +static const char* const BACKEND_BASE_URL = "https://backend.demo.taler.net"; + +static const char* const AUTH_HEADER = "Authorization: ApiKey sandbox"; + +static const char* const JSON_PAID = "paid"; +static const char* const JSON_PAY_URI = "taler_pay_uri"; +static const char* const JSON_ORDER_ID = "order_id"; + + + +//// will be replaced with libjansson functionalites ----------------------------------------------------------------------------------- +// ajust sprintf in taler_create_order_req communication.c if changed +static const char* const JSON_ORDER = "{\n" + " \"order\":" + " {\n" + " \"summary\": \"%s\",\n" + " \"amount\": \"%s:%s\",\n" + " \"fulfillment_url\": \"taler://fulfillment-success/Enjoy+your+%s!\"\n" + " }\n" + "}"; + +#endif // URL_H diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..504c2dd --- /dev/null +++ b/src/main.c @@ -0,0 +1,166 @@ +/* + This file is part of TALER + Copyright (C) 2019 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more +details. + + You should have received a copy of the GNU General Public License +along with + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ + +/** +* @file main.c +* @brief main functionality of the application +* @author BOSS Marco +* @author ... +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <pthread.h> +#include <unistd.h> +#include <nfc/nfc.h> +#include <curl/curl.h> + +#include "nfc-wallet/nfc.h" +#include "taler-processing/communication.h" +#include "taler-processing/product.h" + +const char *CURRENCY = "KUDOS"; + + +ProductOrder product; +nfc_context *context = NULL; + + +void *start_nfc_transmission( void *ignored ) +{ + // supress warning about unused variable + (void)ignored; + + if( pthread_setcanceltype( PTHREAD_CANCEL_ASYNCHRONOUS, NULL ) != 0 ){ + printf( "Error setting thread cancelling type\n"); + } + // start endless transmission loop (until threads gets cancelled) + while( 1 ){ + if( pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL) != 0 ){ + printf("Error setting thread cancelling state\n" ); + } + nfc_transmit( context, product.payUrl, strlen(product.payUrl ) ); + if( pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0){ + printf("Error setting thread cancelling state\n" ); + } + sleep(1); + } + return EXIT_SUCCESS; +} + + +int main( ) +{ + // initialize nfc + nfc_init( &context ); + if( !context ){ + printf( "Unable to init libnfc\n" ); + return EXIT_FAILURE; + } + + // inizialize taler + CURL *curl = NULL; + if( taler_init( &curl ) ){ + printf( "Unable to init taler communication\n" ); + return EXIT_FAILURE; + } + + // inizialize product + if( product_init( &product, CURRENCY ) ){ + printf( "Unable to init product\n" ); + return EXIT_FAILURE; + } + + + while( true ) + { + printf( "Waiting for MBD input\n" ); + printf( "Enter to simulate Snickers, x to quit\n"); + if( getchar() == 'x' ) + break; + + // DEMO snickers + product.amount = "0.1"; + product.product = "Snickers"; + + + // create the order request + taler_create_order_req( &product ); + + // create the order + while( taler_create_order( curl, &product ) ); + + // store the order id into the struct + product_set_order_id( &product ); + + // store the url to check wheter the payment happened or not + product_set_check_url( &product ); + + // check the payment status for the first time + while( taler_check_payment_status( curl, &product ) ); + + // store the url to pay, to do this task the payment status has to be called before, because the url will be in the response + product_set_pay_url( &product ); + + // start a thread to send payment request to taler wallet + pthread_t nfcThread; + if( pthread_create(&nfcThread, NULL, start_nfc_transmission, NULL) ){ + printf( "Could not create thread" ); + return EXIT_FAILURE; + } + + // check the payment status, if paid exit while loop and end thread transmitting nfc messages + while( !product.paid ){ + printf( "Order payment processing\n" ); + fflush(stdout); + sleep(5); + while( taler_check_payment_status( curl, &product ) ); + // set the boolean paid member of ProductOrder struct + product_set_paid_status( &product ); + printf( "Payment status paid: %s\n\n", (product.paid ? "true" : "false") ); + } + printf( "Order no.: %s paid!\n\n", product.orderID ); + + // send cancel request to nfc thread + while( pthread_cancel(nfcThread) != 0 ){ + printf( "Error sending cancel request to thread for nfc transmission" ); + } + void*res; + if( pthread_join( nfcThread, &res ) == 0 ){ + printf( "Thread for nfc transmission finished\n" ); + fflush(stdout); + }else if( res == PTHREAD_CANCELED ){ + printf( "Thread for nfc transmission finished\n" ); + fflush(stdout); + } + + // reset the product + product_reset( &product ); + + } + + // clear all initialized data + nfc_exit( context ); + product_exit( &product ); + taler_exit( &curl ); + + return EXIT_SUCCESS; + +} diff --git a/src/makefile b/src/makefile new file mode 100644 index 0000000..792614d --- /dev/null +++ b/src/makefile @@ -0,0 +1,78 @@ +include target.mk + +APP_NAME = taler-mdb + +SUBDIR_NFC=nfc-wallet +SUBDIR_TAL=taler-processing + +CC = gcc + +# Compiler config +CFLAGS += -Wall +CFLAGS += -O1 +CFLAGS += -I ~/embedded/project/taler-mdb + +CROSS_CFLAGS += -Wall +CROSS_CFLAGS += -O1 +CROSS_CFLAGS += -I ~/libnfc-1.7.0-rc7/include + +# Linker config +LDFLAGS += -lnfc +LDFLAGS += -lcurl +LDFLAGS += -pthread + +CROSS_LDPATH += -L ~/embedded/x-tools/armv8-rpi3-linux-gnueabihf/lib/ + +SOURCES=$(SUBDIR_NFC)/nfc.c $(SUBDIR_NFC)/wallet.c $(SUBDIR_TAL)/product.c $(SUBDIR_TAL)/communication.c main.c + +OBJECTS = $(SOURCES:.c=.o) + +CROSS_OBJECTS = $(SOURCES:.c=.o-$(TARGET_ARCH)) + +SCP = scp +SCPFLAGS = + +.PHONY: mrproper +.PHONY: clean +.PHONY: deploy +.PHONY: target +.PHONY: native + + +all: target native + +native: $(APP_NAME) + +target: $(APP_NAME)-$(TARGET_ARCH) + +deploy: target + @echo "Copy $(TARGET_EXECUTABLE) to $(TARGET_ADDRESS)" + @$(SCP) $(SCPFLAGS) -o User $(TARGET_USER) -o HostName $(TARGET_ADDRESS) -P $(SSH_PORT) $(APP_NAME)-$(TARGET_ARCH) + + +clean: + @find . -iname *.o -exec rm -f {} \; + @find . -iname *.o-* -exec rm -f {} \; + +mrproper: clean + @rm -f $(APP_NAME)-$(TARGET_ARCH) + @rm -f $(APP_NAME) + @find . -iname *~ -exec rm {} \; + + +%.o: %.c + $(CC) $(CFLAGS) -c $< -o $@ + +libnfc-$(TARGET_ARCH) : + + +$(SOURCES:.c=.o-$(TARGET_ARCH)): $(SOURCES) + $(CROSS_TOOLS)/$(CROSS)/bin/$(CROSS)-$(CC) $(CROSS_CFLAGS) -c $< -o $@ + + +$(APP_NAME)-$(TARGET_ARCH): $(CROSS_OBJECTS) + $(CROSS_TOOLS)/$(CROSS)/bin/$(CROSS)-$(CC) $(CROSS_LDPATH) $(LDFLAGS) -o $@ $? + + +$(APP_NAME): $(OBJECTS) + $(CC) -o $@ $? $(LDFLAGS) diff --git a/src/mdb/.gitkeep b/src/mdb/.gitkeep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/mdb/.gitkeep diff --git a/src/nfc-wallet/nfc.c b/src/nfc-wallet/nfc.c new file mode 100644 index 0000000..2b666f2 --- /dev/null +++ b/src/nfc-wallet/nfc.c @@ -0,0 +1,118 @@ +/* + This file is part of TALER + Copyright (C) 2019 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more +details. + + You should have received a copy of the GNU General Public License +along with + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ + +/** +* @file nfc.c +* @brief functions used to comunicate over nfc interface +* @author BOSS Marco +*/ + +#include <string.h> +#include <unistd.h> + +#include "nfc.h" +#include "wallet.h" + + +// upper and lower bounds for mifare targets uid length +#define UID_LEN_UPPER 7 +#define UID_LEN_LOWER 4 + + +int nfc_transmit( nfc_context *context, const char *talerPayUrl, size_t urlSize ) +{ + nfc_device *pnd = NULL; + + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// MEMORY LEAK? NFC OPEN? + + pnd = nfc_open( context, NULL ); // NULL could be replaced with connstring if the correct is known + if( !pnd ){ + printf( "Unable to open NFC device\n" ); + nfc_close( pnd ); + return EXIT_FAILURE; + } + + // initialize device as reader + if( nfc_initiator_init( pnd ) < 0 ){ + nfc_perror( pnd, "nfc_initiator_init" ); + nfc_close( pnd ); + return EXIT_FAILURE; + } + + printf( "Device %s opened: '%s'\n\n", nfc_device_get_name(pnd), nfc_device_get_connstring(pnd) ); + + nfc_target nt; + + // connect to a target device + if( nfc_connect_target( pnd, &nt ) ){ + nfc_close( pnd ); + return EXIT_FAILURE; + }; + + // send the message to the wallet + if( wallet_transmit( pnd, talerPayUrl, urlSize ) ){ + // the transmition failed, the target has to be reselected when using MIFARE as defined in libnfc --> exit + nfc_close( pnd ); + return EXIT_FAILURE; + } + + // clean up + nfc_initiator_deselect_target( pnd ); + nfc_close( pnd ); + + return EXIT_SUCCESS; +} + +int nfc_connect_target( nfc_device *pnd, nfc_target *nt ) +{ + const nfc_modulation nmMifare[] = { { + .nmt = NMT_ISO14443A, + .nbr = NBR_106, + } }; + + printf( "nfc_connect_target: trying to connect to target\n" ); + int ctr = 2; + while( ctr > 0 ){ + // set uid lenght to zero ( in case of second selecting the length still has the old value ) + nt->nti.nai.szUidLen = 0; + if( nfc_initiator_select_passive_target( pnd, nmMifare[0], NULL, 0, nt ) <= 0 ) { + printf( "nfc_connect_target: failed to connect\n" ); + } else if( nt->nti.nai.szUidLen > UID_LEN_UPPER || nt->nti.nai.szUidLen < UID_LEN_LOWER ) { + printf( "nfc_connect_target: failed to connect\n" ); + } else { + printf( "nfc_connect_target: Target selected!\n" ); + nfc_display_target_uid( nt ); + return EXIT_SUCCESS; + } + sleep(1); + ctr--; + } + + return EXIT_FAILURE; +} + +void nfc_display_target_uid( nfc_target *nt ) +{ + printf( "UID: " ); + for ( unsigned int uidPos = 0; uidPos < nt->nti.nai.szUidLen; uidPos++ ) { + printf( "%.2x ", nt->nti.nai.abtUid[uidPos] ); + } + printf("\n\n"); +} + diff --git a/src/nfc-wallet/nfc.h b/src/nfc-wallet/nfc.h new file mode 100644 index 0000000..4416054 --- /dev/null +++ b/src/nfc-wallet/nfc.h @@ -0,0 +1,34 @@ +/* + This file is part of TALER + Copyright (C) 2019 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more +details. + + You should have received a copy of the GNU General Public License +along with + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ + +/** +* @file nfc.h +* @brief functions used to comunicate over nfc interface +* @author BOSS Marco +*/ + +#include <stdlib.h> +#include <stdio.h> +#include <nfc/nfc.h> + +int nfc_transmit( nfc_context *context, const char *talerPayUrl , size_t urlSize ); + +int nfc_connect_target( nfc_device *pnd, nfc_target *nt ); + +void nfc_display_target_uid( nfc_target *nt ); diff --git a/src/nfc-wallet/wallet.c b/src/nfc-wallet/wallet.c new file mode 100644 index 0000000..4b92f7d --- /dev/null +++ b/src/nfc-wallet/wallet.c @@ -0,0 +1,124 @@ +/* + This file is part of TALER + Copyright (C) 2019 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more +details. + + You should have received a copy of the GNU General Public License +along with + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ + +/** +* @file wallet.c +* @brief functions to communicate with taler wallet over nfc +* @author BOSS Marco +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "wallet.h" + + +int wallet_select_aid( nfc_device *pnd ) +{ + uint8_t response[] = { 0x00, 0x00 }; + + int size = sizeof( select_file ) + sizeof( taler_aid ); + uint8_t message[size]; + if( concat_message( select_file, sizeof(select_file), taler_aid, message, size ) ) + return EXIT_FAILURE; + + printf( "wallet_select_aid: Selecting Taler apk using AID: " ); + for( unsigned int i = 0; i < sizeof(taler_aid); ++i ) + printf( "%.2x", taler_aid[i] ); + printf( "\n" ); + + if( nfc_initiator_transceive_bytes( pnd, message, size, response, sizeof(response), TRANSMIT_TIMEOUT ) < 0 ) { + printf( "wallet_select_aid: Failed to select apk\n\n" ); + return EXIT_FAILURE; + } + + return check_response( response, sizeof(response) ); +} + +int wallet_put_message( nfc_device *pnd, const char *msg, size_t msgSize ) +{ + uint8_t response[] = { 0x00, 0x00 }; + + int size = sizeof( put_data ) + msgSize; + uint8_t message[size]; + if( concat_message( put_data, sizeof(put_data), (const uint8_t*)msg, message, size ) ) + return EXIT_FAILURE; + + printf( "wallet_put_messsage: Sending 'PUT DATA' command to wallet\n" ); + + if( nfc_initiator_transceive_bytes( pnd, message, size, response, sizeof(response), TRANSMIT_TIMEOUT ) < 0 ) { + printf( "wallet_put_message: Failed to put message\n\n" ); + return EXIT_FAILURE; + } + + return check_response( response, sizeof(response) ); +} + + +int wallet_transmit( nfc_device *pnd, const char *msg, size_t msgLen ) +{ + if( !msg ) { + printf( "wallet_transmit: No message to send\n\n" ); + return EXIT_FAILURE; + } + + if( wallet_select_aid( pnd ) ) + return EXIT_FAILURE; + printf( "wallet_transmit: Taler wallet apk selected\n\n" ); + if( wallet_put_message( pnd, msg, msgLen ) ) + return EXIT_FAILURE; + printf( "wallet_transmit: Transmitted message to taler wallet\n\n"); + + return EXIT_SUCCESS; +} + +int check_response( uint8_t *response, uint8_t responseLen ) +{ + if( strcmp((char*)response, APDU_SUCCESS ) == 0 ){ + printf("Transmission success\n"); + } else { + printf("Transmission failure, return code: "); + for( uint8_t i = 0; i < responseLen; ++i ){ + printf( "%.2x ", response[i] ); + } + printf("\n"); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} + +int concat_message(const uint8_t* command, size_t commandSize, const uint8_t* message, uint8_t *retMsg, size_t returnSize ) +{ + if( !command || !message ){ + printf( "concat_message: command and message can't be null" ); + return EXIT_FAILURE; + } + + uint8_t i = 0; + for( ; i < commandSize; ++i ){ + retMsg[i] = command[i]; + } + for( ; i < returnSize; ++i){ + retMsg[i] = message[i - commandSize]; + } + + return EXIT_SUCCESS; +} diff --git a/src/nfc-wallet/wallet.h b/src/nfc-wallet/wallet.h new file mode 100644 index 0000000..4d51088 --- /dev/null +++ b/src/nfc-wallet/wallet.h @@ -0,0 +1,57 @@ +/* + This file is part of TALER + Copyright (C) 2019 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more +details. + + You should have received a copy of the GNU General Public License +along with + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ + +/** +* @file wallet.h +* @brief functions to communicate with taler wallet over nfc +* @author BOSS Marco +*/ + +#ifndef WALLET_H +#define WALLET_H + +#include <nfc/nfc.h> + + +// New AID +// static uint8_t taler_aid[] = { 0xF0, 0x00, 0x54, 0x41, 0x4c, 0x45, 0x52 }; + +// Demo AID until uptade +static const uint8_t taler_aid[] = { 0xA0, 0x00, 0x00, 0x02, 0x47, 0x10, 0x01 }; + +#define TRANSMIT_TIMEOUT 500 + +// APDU commands +#define APDU_SUCCESS "\x90\x00" +static const uint8_t select_file[] = { 0x00, 0xA4, 0x04, 0x00, 0x07 }; +static const uint8_t put_data[] = { 0x00, 0xDA, 0x01, 0x00, 0x7c, 0x01 }; + + + +int wallet_select_aid( nfc_device *pnd ); + +int wallet_put_message( nfc_device *pnd, const char *msg, size_t msgSize ); + +int wallet_transmit( nfc_device* pnd, const char *msg, size_t msgLen ); + +int concat_message( const uint8_t* command, size_t commandSize, const uint8_t *message, uint8_t *retMsg, size_t returnSize ); + +int check_response( uint8_t *response, uint8_t responseLen ); + +#endif // WALLET_H diff --git a/src/taler-processing/communication.c b/src/taler-processing/communication.c new file mode 100644 index 0000000..a442a29 --- /dev/null +++ b/src/taler-processing/communication.c @@ -0,0 +1,220 @@ +/* + This file is part of TALER + Copyright (C) 2019 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more +details. + + You should have received a copy of the GNU General Public License +along with + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ + +/** +* @file communication.c +* @brief functions to communicate with taler backend +* @author BOSS Marco +*/ + +#include <string.h> +#include <stdbool.h> + +#include "communication.h" +#include "nfc-wallet/wallet.h" +#include "configuration.h" + +int taler_init(CURL **curl) +{ + if( *curl != NULL ){ + printf( "taler_init: curl handle already initialized\n" ); + return EXIT_FAILURE; + } + + // initialize curl + CURLcode result = curl_global_init( CURL_GLOBAL_ALL ); + *curl = curl_easy_init(); + if( !(*curl) || result != CURLE_OK ){ + printf( "taler_init: could not inizialize curl handle\n" ); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} + +void taler_exit( CURL **curl ) +{ + curl_easy_cleanup(*curl); + curl_global_cleanup(); +} + +int taler_alloc_string( char **string, size_t size ) +{ + *string = malloc( size ); + if( !(*string) ){ + printf( "taler_alloc: unable to allocate string" ); + exit( EXIT_FAILURE ); + } + return EXIT_SUCCESS; +} + +static size_t _taler_write_response( void *contents, size_t size, size_t nmemb, void *userp ) +{ + size_t realSize = size * nmemb; + struct TalerResponse *response = (struct TalerResponse *)userp; + + char *tempString = realloc( response->string, response->size + realSize + 1 ); + if( !tempString ) { + printf( "Allocation failure" ); + return EXIT_FAILURE; + } + + response->string = tempString; + memcpy(&( response->string[response->size] ), contents, realSize ); + response->size += realSize; + response->string[response->size] = 0; + + return realSize; +} + +int taler_create_order_req( ProductOrder *product ) +{ + char buffer[256]; + + sprintf( buffer, JSON_ORDER, product->product, product->currency, product->amount, product->product ); + + char* temp = realloc( product->orderRequest, strlen(buffer) + 1 ); + if( !temp ){ + printf( "could not allocate order\n" ); + return EXIT_FAILURE; + } + + product->orderRequest = temp; + strcpy( product->orderRequest, buffer ); + printf( "Created order Request: \n%s\n\n", product->orderRequest ); + + return EXIT_SUCCESS; +} + +int taler_create_order( CURL *curl, ProductOrder *product ) +{ + // reset the response size + product->response->size = 0; + + // set the url + char url[ strlen(BACKEND_BASE_URL) + strlen( ORDER ) + 1 ]; + sprintf( url, "%s%s", BACKEND_BASE_URL, ORDER ); + curl_easy_setopt( curl, CURLOPT_URL, url ); + + // set the authentication headers + struct curl_slist *list = NULL; + list = curl_slist_append( list, AUTH_HEADER ); + curl_easy_setopt( curl, CURLOPT_HTTPHEADER, list ); + + // curl option "post" + curl_easy_setopt( curl, CURLOPT_HTTPPOST, true ); + curl_easy_setopt( curl, CURLOPT_POSTFIELDS, product->orderRequest ); + + // pass the write function and the struct to write to + curl_easy_setopt( curl, CURLOPT_WRITEFUNCTION, _taler_write_response ); + curl_easy_setopt( curl, CURLOPT_WRITEDATA, (void *)product->response ); + + // perform the call + CURLcode result = curl_easy_perform( curl ); + if( result != CURLE_OK ){ + printf( "could not communicate with \"%s\"\n", url ); + return EXIT_FAILURE; + } + + // reset the curl options + curl_easy_reset( curl ); + + // clean up + curl_slist_free_all( list ); + + return EXIT_SUCCESS; +} + +int taler_check_payment_status( CURL *curl, ProductOrder *product ) +{ + // reset the response size + product->response->size = 0; + + // set the url + curl_easy_setopt( curl, CURLOPT_URL, product->checkUrl ); + + // set the authentication headers + struct curl_slist *list = NULL; + list = curl_slist_append( list, AUTH_HEADER ); + curl_easy_setopt( curl, CURLOPT_HTTPHEADER, list ); + + // curl option "get" + curl_easy_setopt( curl, CURLOPT_HTTPGET, true ); + + // pass the write function and the struct to write to + curl_easy_setopt( curl, CURLOPT_WRITEFUNCTION, _taler_write_response ); + curl_easy_setopt( curl, CURLOPT_WRITEDATA, (void *)product->response ); + + // perform the call + CURLcode result = curl_easy_perform(curl); + if( result != CURLE_OK ){ + printf( "could not communicate with \"%s\"\n", product->checkUrl ); + return EXIT_FAILURE; + } + + // reset the curl options + curl_easy_reset( curl ); + + // clean up + curl_slist_free_all( list ); + + return EXIT_SUCCESS; +} + +int taler_parse_json( const TalerResponse *response, const char *memberName, char **returnStr, bool isBoolean ) +{ + if( !(*returnStr) ) + taler_alloc_string( returnStr, 1 ); + char *result = NULL; + char *temp = NULL; + char mbr[64]; + + if( isBoolean ){ + // If the wanted member is of type boolean + sprintf( mbr, "\"%s\": true", memberName ); + if( (temp = strstr( response->string, mbr)) != NULL ) + result = "true"; + else + result = "false"; + }else{ + // String type members + sprintf( mbr, "\"%s\":", memberName ); + if( (temp = strstr( response->string, mbr )) != NULL ){ + if( (temp = strstr( response->string, ": ")) != NULL ){ + result = strtok( temp, "\""); + result = strtok( NULL, "\""); + } + } + } + if( !result ){ + printf( "taler_parse_json: no member named \"%s\" found!\n\n", memberName ); + return EXIT_FAILURE; + } + temp = realloc( *returnStr, strlen(result) + 1 ); + if( !temp ){ + printf( "taler_parse_json: could not allocate memory for member\n" ); + return EXIT_FAILURE; + } + *returnStr = temp; + strcpy( *returnStr, result ); + + return EXIT_SUCCESS; +} + + diff --git a/src/taler-processing/communication.h b/src/taler-processing/communication.h new file mode 100644 index 0000000..f65b36d --- /dev/null +++ b/src/taler-processing/communication.h @@ -0,0 +1,51 @@ +/* + This file is part of TALER + Copyright (C) 2019 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more +details. + + You should have received a copy of the GNU General Public License +along with + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ + +/** +* @file communication.h +* @brief functions to communicate with taler backend +* @author BOSS Marco +*/ + + +#ifndef COMM_H +#define COMM_H + +#include <stdlib.h> +#include <stdio.h> +#include <stdbool.h> +#include <curl/curl.h> + +#include "product.h" + +int taler_init( CURL **curl ); + +void taler_exit( CURL **curl ); + +int taler_alloc_string( char **string, size_t size ); + +int taler_create_order_req( ProductOrder *product ); + +int taler_create_order( CURL *curl, ProductOrder *product ); + +int taler_check_payment_status( CURL *curl, ProductOrder *product ); + +int taler_parse_json( const TalerResponse *response, const char *memberName, char **returnStr, bool isBoolean ); + +#endif // COMM_H diff --git a/src/taler-processing/product.c b/src/taler-processing/product.c new file mode 100644 index 0000000..5adfc18 --- /dev/null +++ b/src/taler-processing/product.c @@ -0,0 +1,126 @@ +/* + This file is part of TALER + Copyright (C) 2019 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more +details. + + You should have received a copy of the GNU General Public License +along with + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ + +/** +* @file product.c +* @brief defined a product order with the attributes of the product and +the links used to communicate with taler. Provides setter methods to set +the attributes. +* @author BOSS Marco +*/ + +#include <string.h> + +#include "product.h" +#include "configuration.h" +#include "taler-processing/communication.h" + +void product_reset( ProductOrder *product ) +{ + product->amount = NULL; + product->product = NULL; + product->paid = false; +} + +int product_init( ProductOrder *product, const char *currency ) +{ + if( !product ){ + printf( "product_init: product order struct must be provided\n" ); + return EXIT_FAILURE; + } + + // malloc for every string member with size 1, every other func just calls realloc, because this struct gets used over and over again + product->response = malloc( sizeof(TalerResponse) ); + if( !product->response ){ + printf( "product_init: unable to allocate memory for response struct\n" ); + return EXIT_FAILURE; + } + if( taler_alloc_string( &(product->response->string), 1 ) ) + return EXIT_FAILURE; + if( taler_alloc_string( &(product->orderID), 1 ) ) + return EXIT_FAILURE; + if( taler_alloc_string( &(product->orderRequest), 1 ) ) + return EXIT_FAILURE; + if( taler_alloc_string( &(product->payUrl), 1 ) ) + return EXIT_FAILURE; + if( taler_alloc_string( &(product->checkUrl), 1 ) ) + return EXIT_FAILURE; + if( taler_alloc_string( &(product->currency), strlen(currency) + 1 ) ) + return EXIT_FAILURE; + strcpy( product->currency, currency ); + product->amount = NULL; + product->product = NULL; + product->paid = false; + + return EXIT_SUCCESS; +} + +void product_exit( ProductOrder *product ) +{ + free( product->response->string ); + free( product->response ); + free( product->orderID ); + free( product->orderRequest ); + free( product->payUrl ); + free( product->checkUrl ); + free( product->currency ); + product->amount = NULL; + product->product = NULL; + product->paid = false; +} + +int product_set_check_url( ProductOrder *product ) +{ + size_t len = strlen(BACKEND_BASE_URL) + strlen( CHECK ); + char *url = realloc( product->checkUrl, len + strlen(ORDER_CHECK) + strlen(product->orderID) + 1 ); + if( !url ){ + printf( "could not allocate memory for order url\n" ); + return EXIT_FAILURE; + } + + product->checkUrl = url; + sprintf( product->checkUrl, "%s%s%s%s", BACKEND_BASE_URL, CHECK, ORDER_CHECK, product->orderID ); + printf( "Url to check payment: %s\n\n", product->checkUrl ); + + return EXIT_SUCCESS; +} + +int product_set_order_id( ProductOrder *product ) +{ + return taler_parse_json( product->response, JSON_ORDER_ID, &(product->orderID), false ); +} + +int product_set_pay_url( ProductOrder *product ) +{ + return taler_parse_json( product->response, JSON_PAY_URI, &(product->payUrl), false ); +} + +int product_set_paid_status( ProductOrder *product ) +{ + char *temp = NULL; + if( taler_alloc_string( &temp, 1) == EXIT_SUCCESS ){ + taler_parse_json( product->response, JSON_PAID, &temp, true ); + if( strcmp( temp, "true" ) == 0 ) + product->paid = true; + free(temp); + return EXIT_SUCCESS; + } + + return EXIT_FAILURE; +} diff --git a/src/taler-processing/product.h b/src/taler-processing/product.h new file mode 100644 index 0000000..8b8fd61 --- /dev/null +++ b/src/taler-processing/product.h @@ -0,0 +1,67 @@ +/* + This file is part of TALER + Copyright (C) 2019 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more +details. + + You should have received a copy of the GNU General Public License +along with + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ + +/** +* @file product.h +* @brief defined a product order with the attributes of the product and +the links used to communicate with taler. Provides setter methods to set +the attributes. +* @author BOSS Marco +*/ + +#ifndef PRODUCT_H +#define PRODUCT_H + +#include <stdio.h> +#include <stdlib.h> +#include <stdbool.h> + +typedef struct TalerResponse{ + char *string; + size_t size; +} TalerResponse; + +typedef struct ProductOrder{ + char *product; + char *currency; + char *amount; + char *orderRequest; + char *orderID; + char *checkUrl; + char *payUrl; + bool paid; + TalerResponse *response; +} ProductOrder; + + +int product_init( ProductOrder *product, const char* currency ); + +void product_exit( ProductOrder *product ); + +void product_reset( ProductOrder *product ); + +int product_set_check_url( ProductOrder *product ); + +int product_set_order_id( ProductOrder *product ); + +int product_set_pay_url( ProductOrder *product ); + +int product_set_paid_status( ProductOrder *product ); + +#endif // PRODUCT_H diff --git a/src/target.mk b/src/target.mk new file mode 100644 index 0000000..bb77a0f --- /dev/null +++ b/src/target.mk @@ -0,0 +1,6 @@ +TARGET_USER = pi +TARGET_ADDRESS = 192.168.3.10 +SSH_PORT = 22 +CROSS_TOOLS = $(HOME)/embedded/x-tools +CROSS = armv8-rpi3-linux-gnueabihf +TARGET_ARCH = armv8 |