#include #include #include #include #include #include #include #include #include "clog.h" static void getit(struct json_object *new_obj, const char *field); #include "stripe.h" struct MemoryStruct { char *memory; size_t size; }; static size_t WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp) { size_t realsize = size * nmemb; struct MemoryStruct *mem = (struct MemoryStruct *)userp; mem->memory = static_cast(realloc(mem->memory, mem->size + realsize + 1)); if(mem->memory == NULL) { /* out of memory! */ logfmt( logDEBUG, "not enough memory (realloc returned NULL)\n"); return 0; } memcpy(&(mem->memory[mem->size]), contents, realsize); mem->size += realsize; mem->memory[mem->size] = 0; return realsize; } void remove_all_chars(char* str, char c) { char *pr = str, *pw = str; while (*pr) { *pw = *pr++; pw += (*pw != c); } *pw = '\0'; } long stripe_tokenize_card_parse(char *json, char *token, size_t token_size) { long res = -1L; json_object *new_obj; struct json_object *o = NULL; new_obj = json_tokener_parse(json); if (!json_object_object_get_ex(new_obj, "id", &o)) { logfmt( logINFO, "Field id does not exist" ); return res; } enum json_type o_type = json_object_get_type(o); if (strcmp(json_type_to_name(o_type), "string")==0) { snprintf(token, token_size, "%s", json_object_to_json_string(o)); res = 0L; } else { logfmt( logINFO, "Result is not string O__o" ); } /* logfmt(logINFO, "new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); getit(new_obj, "id"); getit(new_obj, "object"); getit(new_obj, "client_ip"); getit(new_obj, "created"); getit(new_obj, "livemode"); getit(new_obj, "type"); getit(new_obj, "used"); */ json_object_put(new_obj); return res; } // https://github.com/json-c/json-c/blob/master/tests/test_cast.c static void getit(struct json_object *new_obj, const char *field) { struct json_object *o = NULL; if (!json_object_object_get_ex(new_obj, field, &o)) printf("Field %s does not exist\n", field); enum json_type o_type = json_object_get_type(o); printf("new_obj.%s json_object_get_type()=%s\n", field, json_type_to_name(o_type)); printf("new_obj.to_string()=%s\n", json_object_to_json_string(o)); printf("new_obj.%s json_object_get_int()=%d\n", field, json_object_get_int(o)); // printf("new_obj.%s json_object_get_int64()=%" PRId64 "\n", field, // json_object_get_int64(o)); printf("new_obj.%s json_object_get_boolean()=%d\n", field, json_object_get_boolean(o)); printf("new_obj.%s json_object_get_double()=%f\n", field, json_object_get_double(o)); } CURL *prepare_curl(char *url, void *chunk) { CURL *curl; /* In windows, this will init the winsock stuff */ curl_global_init(CURL_GLOBAL_ALL); /* get a curl handle */ curl = curl_easy_init(); if(curl) { /* First set the URL that is about to receive our POST. This URL can just as well be a https:// URL if that is what should receive the data. */ curl_easy_setopt(curl, CURLOPT_URL, url); /* send all data to this function */ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback); /* we pass our 'chunk' struct to the callback function */ curl_easy_setopt(curl, CURLOPT_WRITEDATA, chunk); } return curl; } /* curl https://api.stripe.com/v1/tokens \ -u sk_test_MJYII1vrGGr7RrGw1lhYMiTq: \ -d card[number]=4242424242424242 \ -d card[exp_month]=12 \ -d card[exp_year]=2018 \ -d card[cvc]=123 */ long stripe_tokenize_card(const char *key, const char *ccnum, const char *ccexpm, const char *ccexpy, const char *cccvc, char *token, size_t token_size) { CURL *curl; CURLcode res; long ret = -1L; char post_fields[512]; char post_auth[256]; struct MemoryStruct chunk; chunk.memory = static_cast(malloc(1)); /* will be grown as needed by the realloc above */ chunk.size = 0; /* no data at this point */ curl = prepare_curl("https://api.stripe.com/v1/tokens", (void *)&chunk); if(curl) { bzero(post_fields, sizeof(post_fields)); snprintf(post_fields, sizeof(post_fields), "card[number]=%s&card[exp_month]=%s&card[exp_year]=%s&card[cvc]=%s", ccnum, ccexpm, ccexpy, cccvc); /* Now specify the POST data */ curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post_fields); bzero(post_auth, sizeof(post_auth)); snprintf(post_auth, sizeof(post_auth), "%s:", key); /* set user name and password for the authentication */ curl_easy_setopt(curl, CURLOPT_USERPWD, post_auth); /* Perform the request, res will get the return code */ res = curl_easy_perform(curl); /* Check for errors */ if(res == CURLE_OK) { logfmt( logINFO, "%lu bytes retrieved\n", (long)chunk.size); logfmt( logDEBUG, "%s\n", chunk.memory); bzero(token, token_size); ret = stripe_tokenize_card_parse(chunk.memory, token, token_size); if (ret != 0L) { logfmt( logINFO, "Failed to get token"); } } else { logfmt( logINFO, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); } /* always cleanup */ curl_easy_cleanup(curl); free(chunk.memory); } curl_global_cleanup(); return ret; } /* { \"id\": \"card_1BRNdFF5FERRcWDyUdOaIBzd\", \"object\": \"card\", \"address_city\": null, \"address_country\": null, \"address_line1\": null, \"address_line1_check\": null, \"address_line2\": null, \"address_state\": null, \"address_zip\": null, \"address_zip_check\": null, \"brand\": \"American Express\", \"country\": \"US\", \"customer\": \"cus_BoeZzLBOGUiRzw\", \"cvc_check\": null, \"dynamic_last4\": null, \"exp_month\": 8, \"exp_year\": 2019, \"fingerprint\": \"9KROBb1pqZA216C4\", \"funding\": \"credit\", \"last4\": \"8431\", \"metadata\": {}, \"name\": null, \"tokenization_method\": null } */ long stripe_create_card_parse(char *json, char *card, size_t card_size) { long res = -1L; json_object *new_obj; struct json_object *o = NULL; new_obj = json_tokener_parse(json); if (!json_object_object_get_ex(new_obj, "id", &o)) { logfmt( logINFO, "Field ID does not exist\n" ); return res; } enum json_type o_type = json_object_get_type(o); if (strcmp(json_type_to_name(o_type), "string")==0) { snprintf(card, card_size, "%s", json_object_to_json_string(o)); res = 0L; } else { logfmt( logINFO, "ID is not string\n" ); res = -2L; } json_object_put(new_obj); return res; } /* curl https://api.stripe.com/v1/customers/cus_BoeZzLBOGUiRzw/sources \ -u sk_test_MJYII1vrGGr7RrGw1lhYMiTq: \ -d source=tok_amex */ long stripe_create_card(const char *key, char *customer, char *token, char *card, size_t card_size) { CURL *curl; CURLcode res; long ret = -1L; char post_fields[512]; char post_auth[256]; char url[256]; struct MemoryStruct chunk; chunk.memory = static_cast(malloc(1)); /* will be grown as needed by the realloc above */ chunk.size = 0; /* no data at this point */ snprintf(url, sizeof(url), "https://api.stripe.com/v1/customers/%s/sources", customer); curl = prepare_curl(url, (void *)&chunk); if(curl) { bzero(post_fields, sizeof(post_fields)); snprintf(post_fields, sizeof(post_fields), "source=%s", token); /* Now specify the POST data */ curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post_fields); bzero(post_auth, sizeof(post_auth)); snprintf(post_auth, sizeof(post_auth), "%s:", key); /* set user name and password for the authentication */ curl_easy_setopt(curl, CURLOPT_USERPWD, post_auth); /* Perform the request, res will get the return code */ res = curl_easy_perform(curl); /* Check for errors */ if(res == CURLE_OK) { logfmt( logINFO, "%lu bytes retrieved\n", (long)chunk.size); logfmt( logDEBUG, "%s\n", chunk.memory); bzero(card, card_size); ret = stripe_create_card_parse(chunk.memory, card, card_size); if (ret != 0L) { logfmt( logINFO, "Failed to get stripe card ID\n"); } } else { logfmt( logINFO, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); } /* always cleanup */ curl_easy_cleanup(curl); free(chunk.memory); } curl_global_cleanup(); return ret; } /* { \"object\": \"list\", \"data\": [ { \"id\": \"card_1BR1GQF5FERRcWDyp8ncqhzS\", \"object\": \"card\", \"address_city\": null, \"address_country\": null, \"address_line1\": null, \"address_line1_check\": null, \"address_line2\": null, \"address_state\": null, \"address_zip\": null, \"address_zip_check\": null, \"brand\": \"Visa\", \"country\": \"US\", \"customer\": \"cus_BoeZzLBOGUiRzw\", \"cvc_check\": \"pass\", \"dynamic_last4\": null, \"exp_month\": 12, \"exp_year\": 2018, \"fingerprint\": \"VsTJEtWimRlWw8lh\", \"funding\": \"credit\", \"last4\": \"4242\", \"metadata\": {}, \"name\": null, \"tokenization_method\": null } ], \"has_more\": false, \"url\": \"/v1/customers/cus_BoeZzLBOGUiRzw/sources\" } */ long stripe_get_all_cards_parse(char *json, vector *ccids, vector *ccdigits, vector *ccexpm, vector *ccexpy) { long res = -1L; json_object *new_obj; struct json_object *o = NULL; struct json_object *d = NULL; new_obj = json_tokener_parse(json); if (!json_object_object_get_ex(new_obj, "data", &o)) { logfmt( logINFO, "Field data does not exist" ); return res; } enum json_type o_type = json_object_get_type(o); if (strcmp(json_type_to_name(o_type), "array")==0) { //snprintf(token, token_size, "%s", json_object_to_json_string(o)); size_t orig_array_len = json_object_array_length(o); for(size_t i = 0; i < orig_array_len; i++) { json_object *obj = json_object_array_get_idx(o, i); if (json_object_object_get_ex(obj, "id", &d)) { o_type = json_object_get_type(d); if (strcmp(json_type_to_name(o_type), "string")==0) { res = 0L; ccids->push_back(string(json_object_to_json_string(d))); } else { logfmt( logINFO, "Id is not string\n" ); if (res<0L) res = -4L; } } else { logfmt( logINFO, "Id is not found\n" ); if (res<0L) res = -3L; } if (res==0L) { if (json_object_object_get_ex(obj, "exp_month", &d)) { ccexpm->push_back(string(json_object_to_json_string(d))); } if (json_object_object_get_ex(obj, "exp_year", &d)) { ccexpy->push_back(string(json_object_to_json_string(d))); } if (json_object_object_get_ex(obj, "last4", &d)) { ccdigits->push_back(string(json_object_to_json_string(d))); } } } } else { logfmt( logINFO, "Data is not array\n" ); res = -2L; } json_object_put(new_obj); return res; } /* curl "https://api.stripe.com/v1/customers/cus_BoeZzLBOGUiRzw/sources?object=card&limit=3" \ -u sk_test_MJYII1vrGGr7RrGw1lhYMiTq: \ -G */ long stripe_get_all_cards(const char *key, char *customer, vector *ccids, vector *ccdigits, vector *ccexpm, vector *ccexpy) { CURL *curl; CURLcode res; long ret = -1L; //char post_fields[512]; char post_auth[256]; char url[256]; struct MemoryStruct chunk; chunk.memory = static_cast(malloc(1)); /* will be grown as needed by the realloc above */ chunk.size = 0; /* no data at this point */ snprintf(url, sizeof(url), "https://api.stripe.com/v1/customers/%s/sources?object=card&limit=100", customer); curl = prepare_curl(url, (void *)&chunk); if(curl) { /* bzero(post_fields, sizeof(post_fields)); snprintf(post_fields, sizeof(post_fields), "amount=%d¤cy=%s&description=%s&metadata[payment_id]=%s&%s=%s", amount, currency, description, metadata, entity_name, entity); */ /* Now specify the POST data */ // curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post_fields); bzero(post_auth, sizeof(post_auth)); snprintf(post_auth, sizeof(post_auth), "%s:", key); /* set user name and password for the authentication */ curl_easy_setopt(curl, CURLOPT_USERPWD, post_auth); /* Perform the request, res will get the return code */ res = curl_easy_perform(curl); /* Check for errors */ if(res == CURLE_OK) { logfmt( logINFO, "%lu bytes retrieved\n", (long)chunk.size); logfmt( logDEBUG, "%s\n", chunk.memory); //bzero(token2, token2_size); ret = stripe_get_all_cards_parse(chunk.memory, ccids, ccdigits, ccexpm, ccexpy); if (ret != 0L) { logfmt( logINFO, "Failed to load cards for %s\n", customer); } } else { logfmt( logINFO, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); } /* always cleanup */ curl_easy_cleanup(curl); free(chunk.memory); } curl_global_cleanup(); return ret; } long stripe_get_card(const char *key, char *customer, const char *ccdigits, const char *ccexpm, const char *ccexpy, char *card, size_t card_size) { vector vccids; vector vccdigits; vector vccexpm; vector vccexpy; char digits[10]; char year[10]; snprintf(digits, sizeof(digits), "\"%s\"", ccdigits); snprintf(year, sizeof(year), "20%s", ccexpy); long res = stripe_get_all_cards(key, customer, &vccids, &vccdigits, &vccexpm, &vccexpy); size_t cnt = vccids.size(); logfmt( logINFO, "Found %lu card(s)\n", cnt ); if (cnt>0 && vccdigits.size()==cnt && vccexpm.size()==cnt && vccexpy.size()==cnt) { for (int i=0; i'%s'\n'%s'<>'%s'\n'%s'<>'%s'/'%s'\n", vccdigits[i].c_str(), digits, vccexpm[i].c_str(), ccexpm, vccexpy[i].c_str(), ccexpy, year); } } } else { logfmt( logINFO, "No cards loaded\n" ); res = -1L; } return res; } /* \"id\": \"ch_1AwE1GF5FERRcWDyrQ9yxFHO\",\ \"object\": \"charge\",\ \"amount\": 1000,\ \"amount_refunded\": 0,\ \"application\": null,\ \"application_fee\": null,\ \"balance_transaction\": \"txn_1AwE1GF5FERRcWDys1SwbPfO\",\ \"captured\": true,\ \"status\": \"succeeded\" */ long stripe_charge_entity_parse(char *json, char *id, size_t id_size) { long res = -1L; json_object *new_obj; struct json_object *o = NULL; new_obj = json_tokener_parse(json); if (!json_object_object_get_ex(new_obj, "id", &o)) { logfmt( logINFO, "Field id does not exist" ); return res; } enum json_type o_type = json_object_get_type(o); if (strcmp(json_type_to_name(o_type), "string")==0) { snprintf(id, id_size, "%s", json_object_to_json_string(o)); res = 0L; } else { logfmt( logINFO, "Id is not string O__o" ); } if (res==0L) { res = -2L; // Status is not "succeeded" if (!json_object_object_get_ex(new_obj, "status", &o)) { logfmt( logINFO, "Field status does not exist" ); return -3L; } enum json_type status_type = json_object_get_type(o); if (strcmp(json_type_to_name(status_type), "string")==0) { if (strcmp(json_object_to_json_string(o),"\"succeeded\"")==0) { res = 0L; } } else { logfmt( logINFO, "Status is not string O__o" ); res = -4L; } } json_object_put(new_obj); return res; } /* curl https://api.stripe.com/v1/charges \ -u sk_test_MJYII1vrGGr7RrGw1lhYMiTq: \ -d amount=1000 \ -d currency=usd \ -d description="Example charge" \ -d metadata[order_id]=6735 \ -d source=tok_Mk1gcKiXo5zzgR3U9yUmx8jJ */ long stripe_charge_token(const char *key, char *token, int amount, const char *currency, const char *description, const char *metadata, char *id, size_t id_size) { return stripe_charge_real(key, "source", token, amount, currency, description, metadata, id, id_size); } /* curl https://api.stripe.com/v1/charges \ -u sk_test_MJYII1vrGGr7RrGw1lhYMiTq: \ -d amount=1000 \ -d currency=usd \ -d description="Example charge" \ -d metadata[order_id]=6735 \ -d customer=cus_0c0ieRnlG77qkw */ long stripe_charge_customer(const char *key, char *customer, int amount, const char *currency, const char *description, const char *metadata, char *id, size_t id_size) { return stripe_charge_real(key, "customer", customer, amount, currency, description, metadata, id, id_size); } long stripe_charge_real(const char *key, const char *entity_name, char *entity, int amount, const char *currency, const char *description, const char *metadata, char *id, size_t id_size) { CURL *curl; CURLcode res; long ret = -1L; char post_fields[512]; char post_auth[256]; struct MemoryStruct chunk; chunk.memory = static_cast(malloc(1)); /* will be grown as needed by the realloc above */ chunk.size = 0; /* no data at this point */ curl = prepare_curl("https://api.stripe.com/v1/charges", (void *)&chunk); if(curl) { bzero(post_fields, sizeof(post_fields)); snprintf(post_fields, sizeof(post_fields), "amount=%d¤cy=%s&description=%s&metadata[payment_id]=%s&%s=%s", amount, currency, description, metadata, entity_name, entity); /* Now specify the POST data */ curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post_fields); bzero(post_auth, sizeof(post_auth)); snprintf(post_auth, sizeof(post_auth), "%s:", key); /* set user name and password for the authentication */ curl_easy_setopt(curl, CURLOPT_USERPWD, post_auth); /* Perform the request, res will get the return code */ res = curl_easy_perform(curl); /* Check for errors */ if(res == CURLE_OK) { logfmt( logINFO, "%lu bytes retrieved\n", (long)chunk.size); logfmt( logDEBUG, "%s\n", chunk.memory); //bzero(token2, token2_size); ret = stripe_charge_entity_parse(chunk.memory, id, id_size); if (ret != 0L) { logfmt( logINFO, "Failed to charge %s: %s", entity_name, entity); } } else { logfmt( logINFO, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); } /* always cleanup */ curl_easy_cleanup(curl); free(chunk.memory); } curl_global_cleanup(); return ret; } /* "id": "cus_BRNA3itMe3K2qP", "object": "customer", "account_balance": 0, "created": 1505999327, "currency": "usd", "default_source": null, "delinquent": false, "description": null, "discount": null, "email": null, "livemode": false, "metadata": { }, "shipping": null, "sources": { "object": "list", "data": [ ], "has_more": false, "total_count": 0, "url": "/v1/customers/cus_BRNA3itMe3K2qP/sources" }, "subscriptions": { "object": "list", "data": [ ], "has_more": false, "total_count": 0, "url": "/v1/customers/cus_BRNA3itMe3K2qP/subscriptions" */ long stripe_create_customer_parse(char *json, char *id, size_t id_size) { long res = -1L; json_object *new_obj; struct json_object *o = NULL; new_obj = json_tokener_parse(json); if (!json_object_object_get_ex(new_obj, "id", &o)) { logfmt( logINFO, "Field id does not exist" ); return res; } enum json_type o_type = json_object_get_type(o); if (strcmp(json_type_to_name(o_type), "string")==0) { snprintf(id, id_size, "%s", json_object_to_json_string(o)); res = 0L; } else { logfmt( logINFO, "Id is not string O__o" ); } if (res==0L) { res = -2L; // extra check waht we got - customer? if (!json_object_object_get_ex(new_obj, "object", &o)) { logfmt( logINFO, "Field object does not exist" ); return -3L; } enum json_type object_type = json_object_get_type(o); if (strcmp(json_type_to_name(object_type), "string")==0) { if (strcmp(json_object_to_json_string(o),"\"customer\"")==0) { res = 0L; } } else { logfmt( logINFO, "Object is not string O__o" ); res = -4L; } } json_object_put(new_obj); return res; } bool replace(std::string& str, const std::string& from, const std::string& to) { size_t start_pos = str.find(from); if(start_pos == std::string::npos) return false; str.replace(start_pos, from.length(), to); return true; } /* curl https://api.stripe.com/v1/customers \ -u sk_test_MJYII1vrGGr7RrGw1lhYMiTq: \ -d description="Olusesan Ameye" \ -d email="paying.user@example.com" \ -d metadata[customer_id]=6735 \ -d source=tok_udFYcI8zrJp4isLhiWPybdpe */ long stripe_create_customer(const char *key, char *token, const char *email, const char *description, const char *metadata, char *id, size_t id_size) { CURL *curl; CURLcode res; long ret = -1L; char post_fields[512]; char post_auth[256]; struct MemoryStruct chunk; chunk.memory = static_cast(malloc(1)); /* will be grown as needed by the realloc above */ chunk.size = 0; /* no data at this point */ curl = prepare_curl("https://api.stripe.com/v1/customers", (void *)&chunk); if(curl) { bzero(post_fields, sizeof(post_fields)); // Patch email std::string patched_email = email; replace(patched_email, "+", "%2B"); // replace all '+' to '%2B' to avoid "urldecoding" on strip side snprintf(post_fields, sizeof(post_fields), "email=%s&description=%s&metadata[customer_id]=%s&source=%s", patched_email.c_str(), description, metadata, token); /* Now specify the POST data */ curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post_fields); bzero(post_auth, sizeof(post_auth)); snprintf(post_auth, sizeof(post_auth), "%s:", key); /* set user name and password for the authentication */ curl_easy_setopt(curl, CURLOPT_USERPWD, post_auth); /* Perform the request, res will get the return code */ res = curl_easy_perform(curl); /* Check for errors */ if(res == CURLE_OK) { logfmt( logINFO, "%lu bytes retrieved\n", (long)chunk.size); logfmt( logDEBUG, "%s\n", chunk.memory); //bzero(token2, token2_size); ret = stripe_create_customer_parse(chunk.memory, id, id_size); if (ret != 0L) { logfmt( logINFO, "Failed to create customer with token: %s", token); } } else { logfmt( logINFO, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); } /* always cleanup */ curl_easy_cleanup(curl); free(chunk.memory); } curl_global_cleanup(); return ret; } /* See the test_stripe_update_customer_parse() below */ long stripe_update_customer_parse(char *json, const char *result, char *data, size_t data_size) { long res = -1L; json_object *new_obj; struct json_object *o = NULL; new_obj = json_tokener_parse(json); if (!json_object_object_get_ex(new_obj, result, &o)) { logfmt( logINFO, "Field %s does not exist", result ); return res; } res = 0L; enum json_type o_type = json_object_get_type(o); if (strcmp(json_type_to_name(o_type), "string")==0) { snprintf(data, data_size, "%s", json_object_to_json_string(o)); } else if (strcmp(json_type_to_name(o_type), "int")==0) { snprintf(data, data_size, "%d", json_object_get_int(o)); } else if (strcmp(json_type_to_name(o_type), "int64")==0) { snprintf(data, data_size, "%lld", json_object_get_int64(o)); } else if (strcmp(json_type_to_name(o_type), "boolean")==0) { snprintf(data, data_size, "%s", json_object_get_boolean(o) ? "true" : "false"); } else if (strcmp(json_type_to_name(o_type), "double")==0) { snprintf(data, data_size, "%f", json_object_get_double(o)); } else { logfmt( logINFO, "Result is not either string, int, int64, boolean or double: %s", json_type_to_name(o_type) ); res = -2L; } json_object_put(new_obj); return res; } /* curl https://api.stripe.com/v1/customers/cus_BoeZzLBOGUiRzw \ -u sk_test_MJYII1vrGGr7RrGw1lhYMiTq: -d default_source=card_1BR1GQF5FERRcWDyp8ncqhzS */ long stripe_update_customer(const char *key, char *customer, const char *entity, const char *entity_value, const char *result, char *data, size_t data_size) { CURL *curl; CURLcode res; long ret = -1L; char post_fields[512]; char post_auth[256]; char url[256]; struct MemoryStruct chunk; chunk.memory = static_cast(malloc(1)); /* will be grown as needed by the realloc above */ chunk.size = 0; /* no data at this point */ snprintf(url, sizeof(url), "https://api.stripe.com/v1/customers/%s", customer); curl = prepare_curl(url, (void *)&chunk); if(curl) { bzero(post_fields, sizeof(post_fields)); snprintf(post_fields, sizeof(post_fields), "%s=%s", entity, entity_value); /* Now specify the POST data */ curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post_fields); bzero(post_auth, sizeof(post_auth)); snprintf(post_auth, sizeof(post_auth), "%s:", key); /* set user name and password for the authentication */ curl_easy_setopt(curl, CURLOPT_USERPWD, post_auth); /* Perform the request, res will get the return code */ res = curl_easy_perform(curl); /* Check for errors */ if(res == CURLE_OK) { logfmt( logINFO, "%lu bytes retrieved\n", (long)chunk.size); logfmt( logDEBUG, "%s\n", chunk.memory); //bzero(token2, token2_size); ret = stripe_update_customer_parse(chunk.memory, result, data, data_size); if (ret != 0L) { logfmt( logINFO, "Failed to update %s: %s", entity, entity_value); } } else { logfmt( logINFO, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); } /* always cleanup */ curl_easy_cleanup(curl); free(chunk.memory); } curl_global_cleanup(); return ret; } /* American Express 34, 37 China UnionPay 62, 88 Diners ClubCarte Blanche 300-305 Diners Club International 300-305, 309, 36, 38-39 Diners Club US & Canada 54, 55 Discover Card 6011, 622126-622925, 644-649, 65 JCB 3528-3589 Laser 6304, 6706, 6771, 6709 Maestro 5018, 5020, 5038, 5612, 5893, 6304, 6759, 6761, 6762, 6763, 0604, 6390 Dankort 5019 MasterCard 50-55 Visa 4 Visa Electron 4026, 417500, 4405, 4508, 4844, 4913, 4917 */ string stripe_get_card_type(const char *card) { string subject(card); string result; string cards[17] = { "Amex", "BCGlobal", "Carte Blanche", "Diners Club", "Discover", "Insta Payment", "JCB", "KoreanLocalCard", "Laser", "Maestro", "Mastercard", "Solo", "Switch", "Union Pay", "Visa", "Visa Master", "TEST" }; string regexs[17] = { "^3[47][0-9]{13}$", "^(6541|6556)[0-9]{12}$", "^389[0-9]{11}$", "^3(?:0[0-5]|[68][0-9])[0-9]{11}$", "^65[4-9][0-9]{13}|64[4-9][0-9]{13}|6011[0-9]{12}|(622(?:12[6-9]|1[3-9][0-9]|[2-8][0-9][0-9]|9[01][0-9]|92[0-5])[0-9]{10})$", "^63[7-9][0-9]{13}$", "^(?:2131|1800|35[[:digit:]]{3})[[:digit:]]{11}$", "^9[0-9]{15}$", "^(6304|6706|6709|6771)[0-9]{12,15}$", "^(5018|5020|5038|6304|6759|6761|6763)[0-9]{8,15}$", "^5[1-5][0-9]{14}$", "^(6334|6767)[0-9]{12}|(6334|6767)[0-9]{14}|(6334|6767)[0-9]{15}$", "^(4903|4905|4911|4936|6333|6759)[0-9]{12}|(4903|4905|4911|4936|6333|6759)[0-9]{14}|(4903|4905|4911|4936|6333|6759)[0-9]{15}|564182[0-9]{10}|564182[0-9]{12}|564182[0-9]{13}|633110[0-9]{10}|633110[0-9]{12}|633110[0-9]{13}$", "^(62[0-9]{14,17})$", "^4[0-9]{12}(?:[0-9]{3})?$", "^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14})$", "\\.*" }; try { for (int i = 0; i < 17; i++) { //logfmt(logDEBUG, "%s -> %d\n", regexs[i].c_str(), i); pcrecpp::RE r(regexs[i].c_str()); if (r.FullMatch(subject)) { result = cards[i]; break; } } } catch (exception& e) { // Syntax error in the regular expression logfmt(logDEBUG, "regex_error caught: %s\n", e.what()); } return result; } /*****************************************************************************/ #ifdef TEST #warning "Test build with main() entry point" #define STRIPE_KEY "sk_test_MJYII1vrGGr7RrGw1lhYMiTq" long test_stripe_tokenize_card(char *token, size_t token_size) { char *ccnum = "4242424242424242"; char *ccexpm = "12"; char *ccexpy = "18"; char *cccvc = "123"; long res = -1L; res = stripe_tokenize_card(STRIPE_KEY, ccnum, ccexpm, ccexpy, cccvc, token, token_size); logfmt( logINFO, "stripe_tokenize_card(%ld)=%s\n", res, token); return res; } long test_stripe_tokenize_card_parse(void) { char token[256]; long res = -1L; char *json = "{\ \"id\": \"tok_1AwCwAF5FERRcWDyTObhpckX\",\ \"object\": \"token\",\ \"card\": {\ \"id\": \"card_1AwCwAF5FERRcWDyP5OGybH4\",\ \"object\": \"card\",\ \"address_city\": null,\ \"address_country\": null,\ \"address_line1\": null,\ \"address_line1_check\": null,\ \"address_line2\": null,\ \"address_state\": null,\ \"address_zip\": null,\ \"address_zip_check\": null,\ \"brand\": \"Visa\",\ \"country\": \"US\",\ \"cvc_check\": \"unchecked\",\ \"dynamic_last4\": null,\ \"exp_month\": 12,\ \"exp_year\": 2018,\ \"fingerprint\": \"VsTJEtWimRlWw8lh\",\ \"funding\": \"credit\",\ \"last4\": \"4242\",\ \"metadata\": {},\ \"name\": null,\ \"tokenization_method\": null\ },\ \"client_ip\": \"176.117.172.40\",\ \"created\": 1504025498,\ \"livemode\": false,\ \"type\": \"card\",\ \"used\": false\ }"; bzero(token, sizeof(token)); res = stripe_tokenize_card_parse(json, token, sizeof(token)); logfmt( logINFO, "stripe_tokenize_card_parse(%ld)=%s\n", res, token); return res; } long test_stripe_charge_token(char *token, char *id, size_t id_size) { long res = -1L; int amount = 1000; const char *currency = "usd"; const char *description = "Example charge"; const char *metadata = "6735"; res = stripe_charge_token(STRIPE_KEY, token, amount, currency, description, metadata, id, id_size); logfmt( logINFO, "stripe_charge_token(%ld)=%s\n", res, id); return res; } long test_stripe_charge_customer(char *customer, char *id, size_t id_size) { long res = -1L; int amount = 1000; const char *currency = "usd"; const char *description = "Example charge"; const char *metadata = "6735"; res = stripe_charge_customer(STRIPE_KEY, customer, amount, currency, description, metadata, id, id_size); logfmt( logINFO, "stripe_charge_customer(%ld)=%s\n", res, id); return res; } long test_stripe_charge_entity_parse(void) { long res = -1L; char *json = "{\ \"id\": \"ch_1AwE1GF5FERRcWDyrQ9yxFHO\",\ \"object\": \"charge\",\ \"amount\": 1000,\ \"amount_refunded\": 0,\ \"application\": null,\ \"application_fee\": null,\ \"balance_transaction\": \"txn_1AwE1GF5FERRcWDys1SwbPfO\",\ \"captured\": true,\ \"created\": 1504029658,\ \"currency\": \"usd\",\ \"customer\": null,\ \"description\": \"Example charge\",\ \"destination\": null,\ \"dispute\": null,\ \"failure_code\": null,\ \"failure_message\": null,\ \"fraud_details\": {},\ \"invoice\": null,\ \"livemode\": false,\ \"metadata\": {\ \"payment_id\": \"6735\"\ },\ \"on_behalf_of\": null,\ \"order\": null,\ \"outcome\": {\ \"network_status\": \"approved_by_network\",\ \"reason\": null,\ \"risk_level\": \"normal\",\ \"seller_message\": \"Payment complete.\",\ \"type\": \"authorized\"\ },\ \"paid\": true,\ \"receipt_email\": null,\ \"receipt_number\": null,\ \"refunded\": false,\ \"refunds\": {\ \"object\": \"list\",\ \"data\": [],\ \"has_more\": false,\ \"total_count\": 0,\ \"url\": \"/v1/charges/ch_1AwE1GF5FERRcWDyrQ9yxFHO/refunds\"\ },\ \"review\": null,\ \"shipping\": null,\ \"source\": {\ \"id\": \"card_1AwE1GF5FERRcWDyBrNIFHFj\",\ \"object\": \"card\",\ \"address_city\": null,\ \"address_country\": null,\ \"address_line1\": null,\ \"address_line1_check\": null,\ \"address_line2\": null,\ \"address_state\": null,\ \"address_zip\": null,\ \"address_zip_check\": null,\ \"brand\": \"Visa\",\ \"country\": \"US\",\ \"customer\": null,\ \"cvc_check\": null,\ \"dynamic_last4\": null,\ \"exp_month\": 8,\ \"exp_year\": 2019,\ \"fingerprint\": \"VsTJEtWimRlWw8lh\",\ \"funding\": \"credit\",\ \"last4\": \"4242\",\ \"metadata\": {},\ \"name\": null,\ \"tokenization_method\": null\ },\ \"source_transfer\": null,\ \"statement_descriptor\": null,\ \"status\": \"succeeded\",\ \"transfer_group\": null\ }"; char id[256]; bzero(id, sizeof(id)); res = stripe_charge_entity_parse(json, id, sizeof(id)); logfmt( logINFO, "stripe_charge_token_parse(%ld)=%s\n", res, id); return res; } long test_stripe_create_customer(char *token, char *id, size_t id_size) { long res = -1L; char *email = "ameye@chiefsoft"; char *description = "Example Customer"; char *metadata = "6735"; res = stripe_create_customer(STRIPE_KEY, token, email, description, metadata, id, id_size); logfmt( logINFO, "stripe_create_customer(%ld)=%s\n", res, id); return res; } long test_stripe_create_customer_parse() { long res = -1L; char *json = "{\ \"id\": \"cus_BRNA3itMe3K2qP\",\ \"object\": \"customer\",\ \"account_balance\": 0,\ \"created\": 1505999327,\ \"currency\": \"usd\",\ \"default_source\": null,\ \"delinquent\": false,\ \"description\": null,\ \"discount\": null,\ \"email\": null,\ \"livemode\": false,\ \"metadata\": {\ },\ \"shipping\": null,\ \"sources\": {\ \"object\":\"list\",\ \"data\": [\ ],\ \"has_more\": false,\ \"total_count\": 0,\ \"url\": \"/v1/customers/cus_BRNA3itMe3K2qP/sources\"\ },\ \"subscriptions\": {\ \"object\": \"list\",\ \"data\": [\ ],\ \"has_more\": false,\ \"total_count\": 0,\ \"url\": \"/v1/customers/cus_BRNA3itMe3K2qP/subscriptions\"\ }\ }"; char id[256]; bzero(id, sizeof(id)); res = stripe_create_customer_parse(json, id, sizeof(id)); logfmt( logINFO, "\nstripe_create_customer_parse(%ld)=%s\n", res, id); return res; } long test_stripe_get_card(char *customer, char *card, size_t card_size) { char *ccdigits = "4242"; char *ccexpm = "12"; char *ccexpy = "18"; long res = -1L; res = stripe_get_card(STRIPE_KEY, customer, ccdigits, ccexpm, ccexpy, card, card_size); logfmt( logINFO, "stripe_get_card(%ld)=%s\n", res, card); return res; } long test_stripe_get_all_cards_parse() { long res = -1L; char *json = "{\ \"object\": \"list\",\ \"data\": [\ {\ \"id\": \"card_1BR1GQF5FERRcWDyp8ncqhzS\",\ \"object\": \"card\",\ \"address_city\": null,\ \"address_country\": null,\ \"address_line1\": null,\ \"address_line1_check\": null,\ \"address_line2\": null,\ \"address_state\": null,\ \"address_zip\": null,\ \"address_zip_check\": null,\ \"brand\": \"Visa\",\ \"country\": \"US\",\ \"customer\": \"cus_BoeZzLBOGUiRzw\",\ \"cvc_check\": \"pass\",\ \"dynamic_last4\": null,\ \"exp_month\": 12,\ \"exp_year\": 2018,\ \"fingerprint\": \"VsTJEtWimRlWw8lh\",\ \"funding\": \"credit\",\ \"last4\": \"4242\",\ \"metadata\": {},\ \"name\": null,\ \"tokenization_method\": null\ }\ ],\ \"has_more\": false,\ \"url\": \"/v1/customers/cus_BoeZzLBOGUiRzw/sources\"\ }"; vector vccids; vector vccdigits; vector vccexpm; vector vccexpy; res = stripe_get_all_cards_parse(json, &vccids, &vccdigits, &vccexpm, &vccexpy); logfmt( logINFO, "\nstripe_get_all_cards_parse(%ld):\n", res); if (vccids.size()>0) { for (int i=0; i