431 lines
14 KiB
C++
431 lines
14 KiB
C++
// Topup management toosl
|
|
#include "clog.h"
|
|
#include "cgi.h"
|
|
#include "cfg.h"
|
|
#include "input.h"
|
|
#include "wrenchboard_api.h"
|
|
#include "bko.h"
|
|
#include "account.h"
|
|
#include "email.h"
|
|
#include "safestring.h"
|
|
#include "hmac_sha2.h"
|
|
#include <string>
|
|
#include "pgsql.h"
|
|
#include "pgsql_wrapper.h"
|
|
#include "payments.h"
|
|
|
|
#include "php.h"
|
|
#include <curl/curl.h>
|
|
#include "account.h"
|
|
|
|
long BkoCommonSessionCheck(long backoffice_id,long shop,long acc, const char *sessionid, int create );
|
|
long BkoResendOffer(CVars in, CVars &out);
|
|
long BkoRefreshWallet(CVars in, CVars &out);
|
|
long BkoResendMarketing(CVars in, CVars &out);
|
|
|
|
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 = (char*) realloc(mem->memory, mem->size + realsize + 1);
|
|
if (mem->memory == NULL) {
|
|
/* out of memory! */
|
|
logfmt(logINFO, "not enough memory (realloc returned NULL)");
|
|
return 0;
|
|
}
|
|
|
|
memcpy(&(mem->memory[mem->size]), contents, realsize);
|
|
mem->size += realsize;
|
|
mem->memory[mem->size] = 0;
|
|
|
|
return realsize;
|
|
}
|
|
|
|
long bko_calls(CVars in, CVars &out)
|
|
{
|
|
logfmt( logINFO, "bko_calls()" );
|
|
out["result"] = "YES I GET TO BACK END";
|
|
long action = REQ_LONG( in, "action", 0, -1);
|
|
switch( action )
|
|
{
|
|
case WRENCHBOARD_BKO_LOGIN:
|
|
return LoginBkoAdmin( in, out);
|
|
break;
|
|
|
|
case WRENCHBOARD_BKO_RESEND_OFFER:
|
|
return BkoResendOffer( in, out);
|
|
break;
|
|
|
|
case WRENCHBOARD_BKO_MARKETING_MSG:
|
|
return BkoResendMarketing( in, out );
|
|
break;
|
|
|
|
case WRENCHBOARD_BKO_SEND_PUSH:
|
|
return BkoSendPush( in, out);
|
|
break;
|
|
|
|
case WRENCHBOARD_BKO_REFRESH_WALLET:
|
|
return BkoRefreshWallet(in, out);
|
|
break;
|
|
}
|
|
logfmt( logINFO, "/bko_calls()" );
|
|
return 0;
|
|
}
|
|
|
|
long BkoRefreshWallet(CVars in, CVars &out)
|
|
{
|
|
logfmt( logINFO, "BkoRefreshWallet()" );
|
|
REQ_STRING (in, "uid", 5, 149, "(.*)");
|
|
CVars x;
|
|
|
|
long member_id = REQ_LONG( in, "member_id", 0, -1);
|
|
REQ_STRING (in, "member_uid", 9, 49, "(.*)");
|
|
|
|
if ( load_db_record( x, "SELECT * FROM members WHERE uid='%s' AND id =%lu", in["member_uid"].c_str(),in["member_id"].Long() )){
|
|
CVars vw;
|
|
load_db_record(vw, "SELECT code AS currency FROM currency WHERE country='%s'",x["country"].c_str());
|
|
if ( vw["currency"] !=""){
|
|
vw["currency"].set_valid( true );
|
|
out["wallet_id"] = CheckWallet(member_id,vw);
|
|
}
|
|
}
|
|
logfmt( logINFO, "/BkoRefreshWallet()" );
|
|
return 0;
|
|
}
|
|
|
|
|
|
long BkoResendMarketing(CVars in, CVars &out)
|
|
{
|
|
logfmt( logINFO, "BkoResendMarketing()" );
|
|
REQ_STRING (in, "uid", 5, 149, "(.*)");
|
|
CVars x;
|
|
|
|
if ( load_db_record( x, "SELECT * FROM marketing_list WHERE uid='%s'", in["uid"].c_str() )){
|
|
market_email(WRENCHBOARD_BKO_MARKETING_MSG, x, out);
|
|
}
|
|
|
|
|
|
logfmt( logINFO, "/BkoResendMarketing()" );
|
|
return 0;
|
|
}
|
|
|
|
long BkoResendOffer(CVars in, CVars &out)
|
|
{
|
|
logfmt( logINFO, "BkoResendOffer()" );
|
|
REQ_STRING (in, "offer_code", 5, 49, "(.*)");
|
|
CVars x;
|
|
|
|
if ( load_db_record( x, "SELECT id AS offer_id FROM members_jobs_offer WHERE offer_code='%s'", in["offer_code"].c_str() )){
|
|
//ret = PHP_CREATED_OK;
|
|
//x["offer_id"] = offer_id;
|
|
//x["offer_id"].set_valid(true);
|
|
job_email(JOBS_INDIVIDUAL_OFFER_MAIL, x, out);
|
|
}
|
|
|
|
|
|
logfmt( logINFO, "/BkoResendOffer()" );
|
|
return 0;
|
|
}
|
|
|
|
long BkoSendPush(CVars in, CVars &out)
|
|
{
|
|
logfmt( logINFO, "BkoSendPush()" );
|
|
long ret = PHP_API_BAD_PARAM;
|
|
REQ_STRING (in, "member_uid", 9, 49, "(.*)");
|
|
REQ_STRING (in, "push_text", 5, 249, "(.*)");
|
|
|
|
const char *onesignal_app_id = CfgReadChar("onesignal.app_id");
|
|
const char *onesignal_api_key = CfgReadChar("onesignal.api_key");
|
|
|
|
CURL *curl;
|
|
CURLcode res;
|
|
|
|
struct MemoryStruct chunk;
|
|
|
|
chunk.memory = (char*) malloc(1); /* will be grown as needed by the realloc above */
|
|
chunk.size = 0; /* no data at this point */
|
|
|
|
curl_global_init(CURL_GLOBAL_ALL);
|
|
|
|
/* get a curl handle */
|
|
curl = curl_easy_init();
|
|
|
|
if (curl) {
|
|
// Prepare data
|
|
string data = "";
|
|
// https://www.php.net/hash_hmac
|
|
/*
|
|
zval algo, value, key, function_name;
|
|
ZVAL_STRING(&algo, "sha256");
|
|
ZVAL_STRING(&value, in["member_uid"].c_str());
|
|
ZVAL_STRING(&key, "YzczOTA0YmYtMjZkOC00MWFlLTgxMTYtNzNhMzg2NGY1Mjli");
|
|
ZVAL_STRING(&function_name, "hash_hmac");
|
|
|
|
// zval params = { algo, value, key };
|
|
zval params;
|
|
ZVAL_ARR(¶ms, zend_new_array(3));
|
|
|
|
int param_count = 3;
|
|
zval *retval_ptr;
|
|
|
|
// ZVAL_COPY(¶ms[0], &algo);
|
|
Z_TRY_ADDREF(algo);
|
|
add_index_zval(¶ms, 0, &algo);
|
|
Z_TRY_ADDREF(value);
|
|
add_index_zval(¶ms, 1, &value);
|
|
Z_TRY_ADDREF(key);
|
|
add_index_zval(¶ms, 2, &key);
|
|
*/
|
|
/*
|
|
if (call_user_function(CG(function_table), NULL, &function_name, retval_ptr, param_count, ¶ms TSRMLS_CC) == SUCCESS) {
|
|
zend_string *member_uid_hash = Z_STR(*retval_ptr);
|
|
out["member_uid_hash"] = ZSTR_VAL(member_uid_hash);
|
|
}
|
|
|
|
zval_ptr_dtor(&value);
|
|
ZVAL_STRING(&value, in["push_text"].c_str());
|
|
//ZVAL_COPY(¶ms[1], &value);
|
|
Z_TRY_ADDREF(value);
|
|
add_index_zval(¶ms, 1, &value);
|
|
|
|
if (call_user_function(CG(function_table), NULL, &function_name, retval_ptr, param_count, ¶ms TSRMLS_CC) == SUCCESS) {
|
|
zend_string *push_text_hash = Z_STR(*retval_ptr);
|
|
out["push_text_hash"] = ZSTR_VAL(push_text_hash);
|
|
}
|
|
*/
|
|
/*
|
|
zval_ptr_dtor(&algo);
|
|
zval_ptr_dtor(&value);
|
|
zval_ptr_dtor(&key);
|
|
zval_ptr_dtor(retval_ptr);
|
|
zval_ptr_dtor(&function_name);
|
|
|
|
//zval_ptr_dtor(params[0]);
|
|
//zval_ptr_dtor(params[1]);
|
|
//zval_ptr_dtor(params[2]);
|
|
//efree(params); // free container
|
|
zval_ptr_dtor(¶ms);
|
|
*/
|
|
//in["member_uid"] = "e30c6484-a70e-4d2b-9932-347999e81d7a";
|
|
//out["member_uid_hash"] = "71298987653243bc7b27f1e06b221a872203e7b78093e85c2a996f3b7885fde0";
|
|
//in["push_text"] = "English or Any Language Message";
|
|
//out["push_text_hash"] = "9ea7a84fdcc3682b60f2072536a24efedaa25fb5b4cad3a9c6c684533ce23967";
|
|
/*
|
|
hmac_sha256(unsigned char *key, unsigned int key_size,
|
|
unsigned char *message, unsigned int message_len,
|
|
unsigned char *mac, unsigned mac_size);
|
|
*/
|
|
unsigned mac_size = SHA256_DIGEST_SIZE; // 256 / 8 = 32 bytes
|
|
unsigned char buffer[mac_size];
|
|
bzero(buffer, mac_size);
|
|
hmac_sha256((unsigned char*)onesignal_api_key, strlen(onesignal_api_key), (unsigned char*)in["member_uid"].c_str(), strlen(in["member_uid"].c_str()), buffer, mac_size);
|
|
|
|
std::size_t buffer_size = mac_size; // strlen((const char *)buffer);
|
|
char member_uid[buffer_size * 2 + 1];
|
|
bzero(member_uid, sizeof(member_uid));
|
|
for(int i = 0; i < buffer_size; i++)
|
|
{
|
|
sprintf(&member_uid[2*i], "%02X", buffer[i]);
|
|
}
|
|
|
|
out["member_uid_hash"] = member_uid;
|
|
logfmt(FLOG_MAX, "\nraw=%s\nencoder = %s\nout = %s\n", buffer, member_uid, out["member_uid_hash"].c_str());
|
|
|
|
bzero(buffer, mac_size);
|
|
hmac_sha256((unsigned char*)onesignal_api_key, strlen(onesignal_api_key), (unsigned char*)in["push_text"].c_str(), strlen(in["push_text"].c_str()), buffer, mac_size);
|
|
|
|
buffer_size = mac_size; // strlen((const char *)buffer);
|
|
char push_text[buffer_size * 2 + 1];
|
|
bzero(push_text, sizeof(push_text));
|
|
for(int i = 0; i < buffer_size; i++)
|
|
{
|
|
sprintf(&push_text[2*i], "%02X", buffer[i]);
|
|
}
|
|
|
|
out["push_text_hash"] = push_text;
|
|
logfmt(FLOG_MAX, "\nraw=%s\nencoded = %s\nout = %s\n", buffer, push_text, out["push_text_hash"].c_str());
|
|
|
|
|
|
data += "{\"include_aliases\": {\"external_id\": [\"";
|
|
data += in["member_uid"].c_str();
|
|
data += "\"],\"external_id_auth_hash\": [\"";
|
|
data += out["member_uid_hash"].c_str();
|
|
data += "\"]},\"target_channel\": \"push\",\"contents\": {\"en\": \"";
|
|
data += in["push_text"].c_str();
|
|
data += "\",\"en_auth_hash\": \"";
|
|
data += out["push_text_hash"].c_str();
|
|
data += "\"},\"app_id\": \"";
|
|
data += onesignal_app_id;
|
|
data += "\"}";
|
|
|
|
logfmt(logINFO, "DATA: %s", data.c_str());
|
|
|
|
string auth = "Authorization: Basic ";
|
|
auth += onesignal_api_key;
|
|
|
|
struct curl_slist *headerlist=NULL;
|
|
headerlist = curl_slist_append(headerlist, auth.c_str());
|
|
headerlist = curl_slist_append(headerlist, "accept: application/json");
|
|
headerlist = curl_slist_append(headerlist, "content-type: application/json");
|
|
|
|
curl_easy_setopt(curl, CURLOPT_URL, "https://onesignal.com/api/v1/notifications");
|
|
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data.c_str());
|
|
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist);
|
|
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
|
|
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *) &chunk);
|
|
res = curl_easy_perform(curl);
|
|
if (res != CURLE_OK) {
|
|
// Error
|
|
out["status"] = curl_easy_strerror(res);
|
|
logfmt(logINFO, "ERROR: %s", out["status"].c_str());
|
|
ret = PHP_API_BAD_PARAM;
|
|
} else {
|
|
logfmt(logINFO, "%lu bytes retrieved\n", (long) chunk.size);
|
|
data = (const char *) chunk.memory;
|
|
istringstream buffer(data);
|
|
string temp, val;
|
|
size_t found, found2;
|
|
while (std::getline(buffer, temp)) {
|
|
logfmt(logINFO, "line: %s", temp.c_str());
|
|
found = temp.find_first_of("\"id\":\"");
|
|
found2 = temp.find_first_of("\"", found + 7);
|
|
if (found > 0 && (found2 - found - 5) > 0) {
|
|
val = temp.substr(found + 8, found2 - found - 8);
|
|
out["onesignal_message_id"] = val;
|
|
logfmt(logINFO, "id => '%s'", out["onesignal_message_id"].c_str());
|
|
}
|
|
}
|
|
ret = PHP_API_OK;
|
|
}
|
|
|
|
curl_slist_free_all(headerlist);
|
|
curl_easy_cleanup(curl);
|
|
|
|
if (chunk.memory) {
|
|
free(chunk.memory);
|
|
}
|
|
}
|
|
curl_global_cleanup();
|
|
|
|
logfmt( logINFO, "/BkoSendPush()" );
|
|
return ret;
|
|
}
|
|
|
|
long LoginBkoAdmin(CVars in, CVars &out)
|
|
{
|
|
long ret = PHP_API_BAD_PARAM;
|
|
logfmt( logINFO, "LoginBkoAdmin()" );
|
|
REQ_STRING (in, "username", 5, 49, "(.*)");
|
|
REQ_STRING (in, "password", 5, 49, "(.*)");
|
|
//REQ_STRING (in, "sessionid", 4, 40, "(.*)");
|
|
const char * loc = getenv("REMOTE_ADDR");
|
|
|
|
load_db_record( out, "SELECT md5( md5('now()')||'%d' ) AS sessionid",rand()*10000);
|
|
in["sessionid"] = out["sessionid"]; in["sessionid"].set_valid( true );
|
|
|
|
|
|
ret = load_db_record( out, "SELECT *,id AS backoffice_id "
|
|
" FROM backoffice WHERE status=1 "
|
|
" AND LOWER(username)=LOWER('%s') AND pass= md5('%s')", in["username"].c_str(), in["password"].c_str() );
|
|
if (ret>0) {
|
|
if (BkoCommonSessionCheck(out["id"].Long(),0,0, in["sessionid"].c_str(), 1)>0) {
|
|
pgsql_exec("UPDATE backoffice SET last_login=NOW() WHERE id=%ld AND uid='%s'", out["backoffice_id"].Long(), out["uid"].c_str());
|
|
out["stauts"] = "OK";
|
|
ret = PHP_API_OK;
|
|
} else {
|
|
out["status"] = "Session check failed";
|
|
}
|
|
} else {
|
|
out["status"] = "Invalid username and/or password";
|
|
}
|
|
|
|
logfmt( logINFO, "/LoginBkoAdmin()" );
|
|
return ret;
|
|
}
|
|
|
|
|
|
long BkoCommonSessionCheck(long backoffice_id,long shop,long acc, const char *sessionid, int create )
|
|
{
|
|
logfmt( logINFO, "long BkoCommonSessionCheck(long backoffice_id,long shop, const char *sessionid, int create )" );
|
|
// Sanity check
|
|
if (backoffice_id<1 || sessionid==NULL || strlen(sessionid)<4) {
|
|
return -1L; // Invalif parameters
|
|
}
|
|
|
|
char ptid[30];
|
|
if ( shop > 0 )
|
|
{
|
|
sprintf( ptid, " AND shop=%lu ", shop );
|
|
}
|
|
else
|
|
{
|
|
sprintf( ptid, " " ); // just empty space
|
|
}
|
|
// Clean old sessions
|
|
if (create>0)
|
|
{ pgsql_exec("DELETE FROM backoffice_session WHERE backoffice_id=%ld %s ", backoffice_id,ptid); }
|
|
else
|
|
{ pgsql_exec("DELETE FROM backoffice_session WHERE backoffice_id=%ld %s AND updated < (now() - interval '15 minutes')", backoffice_id,ptid); }
|
|
|
|
if (create==0 && pgsql_exec("UPDATE backoffice_session SET updated=NOW() WHERE backoffice_id=%ld %s AND sessionid='%s'", backoffice_id,ptid, sessionid)>0) {
|
|
return 1L; // Session updated
|
|
}
|
|
if (create>0) {
|
|
// Check session i?
|
|
/*
|
|
const PGresult *res = pgsql_query("SELECT * FROM backoffice_session WHERE backoffice_id=%ld %s AND sessionid<>'%s'", backoffice_id,ptid, sessionid);
|
|
if (res!=NULL && pgsql_num_rows(res)>0) {
|
|
return -2L; // Active sessions found
|
|
}
|
|
*/
|
|
CVars sess; // Do we have the same session already?
|
|
if (load_db_record( sess, "SELECT * FROM backoffice_session WHERE backoffice_id=%lu %s AND sessionid='%s'", backoffice_id,ptid, sessionid)>0) {
|
|
pgsql_exec("UPDATE backoffice_session SET updated=NOW() WHERE backoffice_id=%ld %s AND sessionid='%s'", backoffice_id,ptid, sessionid);
|
|
return sess["id"].Long();
|
|
}
|
|
// Create a new session
|
|
sess["backoffice_id"] = backoffice_id; sess["backoffice_id"].set_valid(true);
|
|
sess["sessionid"] = sessionid; sess["sessionid"].set_valid(true);
|
|
const char * loc = getenv("REMOTE_ADDR");
|
|
sess["loc"] = loc; sess["loc"].set_valid(true);
|
|
|
|
if ( shop > 0 )
|
|
{
|
|
sess["shop"] = shop; sess["shop"].set_valid(true);
|
|
}
|
|
if ( acc > 0 )
|
|
{
|
|
sess["account"] = acc; sess["account"].set_valid(true);
|
|
}
|
|
long sid = insert_db_record( DBS_VALID, "backoffice_session", "backoffice_session_id_seq", sess );
|
|
if (sid>0) {
|
|
return sid; // New session created
|
|
}
|
|
return -3L; // Failed to create new session
|
|
}
|
|
logfmt( logINFO, "/long BkoCommonSessionCheck(long backoffice_id,long shop, const char *sessionid, int create )" );
|
|
return 0L; // No route
|
|
}
|
|
|
|
/*
|
|
|
|
CREATE TABLE backoffice_session (
|
|
id SERIAL,
|
|
backoffice_id INT REFERENCES managers(id),
|
|
shop INT DEFAULT 0,
|
|
sessionid varchar(100) NOT NULL,
|
|
added timestamp without time zone DEFAULT now(),
|
|
updated timestamp without time zone DEFAULT now(),
|
|
status integer DEFAULT 1,
|
|
loc INET
|
|
);
|
|
|
|
|
|
*/
|