#include "stdafx.h"
#include "rapidjson/rapidjson.h"
#include "rapidjson/document.h"
#include "rapidjson/stringbuffer.h"
#include "rapidjson/writer.h"
#include "crypto.h"
#include <locale>
#include <codecvt>
#include <iomanip>
void replaceall(std::string& str,const std::string& old_value,const std::string& new_value)
{
while(true){
std::string::size_type pos(0);
if((pos = str.find(old_value)) != std::string::npos)
str.replace(pos,old_value.length(),new_value);
else
break;
}
}
std::string getUUID() {
#ifdef WIN32
char buffer[GUID_LEN] = { 0 };
GUID guid;
if (CoCreateGuid(&guid))
{
fprintf(stderr, "create guid error\n");
return "";
}
_snprintf(buffer, sizeof(buffer),
"%08X-%04X-%04x-%02X%02X-%02X%02X%02X%02X%02X%02X",
guid.Data1, guid.Data2, guid.Data3,
guid.Data4[0], guid.Data4[1], guid.Data4[2],
guid.Data4[3], guid.Data4[4], guid.Data4[5],
guid.Data4[6], guid.Data4[7]);
printf("guid: %s\n", buffer);
return std::string(buffer);
#else
uuid_t uuid;
uuid_generate(uuid);
char buf[64] = { 0 };
uuid_unparse(uuid, buf);
return std::string(buf);
#endif
};
std::string base64Encode(const unsigned char* Data,int DataByte)
{
//编码表
const char EncodeTable[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
//返回值
std::string strEncode;
unsigned char Tmp[4]={0};
int LineLength=0;
for(int i=0;i<(int)(DataByte / 3);i++)
{
Tmp[1] = *Data++;
Tmp[2] = *Data++;
Tmp[3] = *Data++;
strEncode+= EncodeTable[Tmp[1] >> 2];
strEncode+= EncodeTable[((Tmp[1] << 4) | (Tmp[2] >> 4)) & 0x3F];
strEncode+= EncodeTable[((Tmp[2] << 2) | (Tmp[3] >> 6)) & 0x3F];
strEncode+= EncodeTable[Tmp[3] & 0x3F];
if(LineLength+=4,LineLength==76) {LineLength=0;}
}
//对剩余数据进行编码
int Mod=DataByte % 3;
if(Mod==1)
{
Tmp[1] = *Data++;
strEncode+= EncodeTable[(Tmp[1] & 0xFC) >> 2];
strEncode+= EncodeTable[((Tmp[1] & 0x03) << 4)];
strEncode+= "==";
}
else if(Mod==2)
{
Tmp[1] = *Data++;
Tmp[2] = *Data++;
strEncode+= EncodeTable[(Tmp[1] & 0xFC) >> 2];
strEncode+= EncodeTable[((Tmp[1] & 0x03) << 4) | ((Tmp[2] & 0xF0) >> 4)];
strEncode+= EncodeTable[((Tmp[2] & 0x0F) << 2)];
strEncode+= "=";
}
return strEncode;
}
std::string sha256(const std::string& str)
{
BYTE hash[SHA256_BLOCK_SIZE];
_SHA256_CTX sha;
sha256_init(&sha);
sha256_update(&sha, (unsigned char*)str.c_str(), str.size());
sha256_final(&sha, hash);
std::stringstream ss;
for(int i = 0; i < SHA256_BLOCK_SIZE; i++)
ss << std::hex << std::setw(2) << std::setfill('0') << (int)hash[i];
return ss.str();
}
std::string buildWSSEHeader(const std::string& appKey, const std::string& appSecret)
{
time_t _t = time(NULL);
char bufTime[64] = { 0 };
struct tm _tt;
localtime_s(&_tt, &_t);
sprintf(bufTime, "%04d-%02d-%02dT%02d:%02d:%02dZ",_tt.tm_year+1900,_tt.tm_mon+1,_tt.tm_mday,_tt.tm_hour,_tt.tm_min,_tt.tm_sec);
std::string now(bufTime);
std::string nonce = getUUID();
replaceall(nonce,"-", "");
std::string sum_data = StringHelper::AnsiiToUtf8(nonce + now + appSecret);
std::string hexdigest = sha256(sum_data);
replaceall(hexdigest,"-", "");
std::string base64 = base64Encode((unsigned char*)hexdigest.c_str(), hexdigest.size());
char szHeadParams[1024];
_snprintf(szHeadParams, CountArray(szHeadParams), "X-WSSE: UsernameToken Username=\"%s\",PasswordDigest=\"%s\",Nonce=\"%s\",Created=\"%s\"",
appKey.c_str(), base64.c_str(), nonce.c_str(), now.c_str());
std::string strParams = StringHelper::AnsiiToUtf8(szHeadParams);
return strParams;
}
int main(void)
{
CURL *curl;
CURLcode res;
std::wstring wstrParams = TEXT("");
std::string strParams = "";
TCHAR szpostParams[1024] = {0};
//主要配置在下面有5个,都可以从华为云上获取,不过都要审核
std::string appKey = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
std::string appSecret= "YYYYYYYYYYYYYYYYYYYYYYYYYYYY";
TCHAR templateId[64] = TEXT("AAAAAAAAAAAAAAAAAA");
TCHAR sender[64] = TEXT("1256856");
TCHAR signature[64] = TEXT("模板名字");
TCHAR szMobile[64] = TEXT("13500000000");
TCHAR szVerifyCode[64] = TEXT("1233456"); //注意这里的位数一定要和模板里面的位数是一样的,不然会报错
SYSTEMTIME systime;
std::string strResponseUTF8="";
std::string strResponse="";
_sntprintf(szpostParams, CountArray(szpostParams), TEXT("from=%s&to=%s&templateId=%s&templateParas=[\"%s\"]&statusCallback=%s&signature=%s"),
sender, szMobile, templateId, szVerifyCode, TEXT(""),signature);
//字符集转换
static std::wstring_convert<std::codecvt_utf8<wchar_t>> wsc;
//strParams = StringHelper::UnicodeToUtf8(szpostParams);
strParams = wsc.to_bytes(szpostParams) ;
curl = curl_easy_init();
if(curl)
{
struct curl_slist* header_ = curl_slist_append(NULL,"Content-Type: application/x-www-form-urlencoded");
curl_slist_append(header_, "Authorization:WSSE realm=\"SDP\",profile=\"UsernameToken\",type=\"Appkey\"");
curl_slist_append(header_, buildWSSEHeader(appKey, appSecret).c_str());
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header_);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
curl_easy_setopt(curl, CURLOPT_URL, "https://rtcsms.cn-north-1.myhuaweicloud.com:10743/sms/batchSendSms/v1");
curl_easy_setopt(curl, CURLOPT_NOBODY, 0L);
curl_easy_setopt(curl, CURLOPT_NOSIGNAL,1L);
curl_easy_setopt(curl, CURLOPT_POST, 1);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, strParams.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &CSMSManager::cbFuncWrite);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (VOID*)&strResponseUTF8);
curl_easy_setopt(curl, CURLOPT_VERBOSE, 0L);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
curl_easy_setopt(curl, CURLOPT_MAXREDIRS,10);
curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, 2000);
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT_MS, 1000);
curl_easy_setopt(curl, CURLOPT_DNS_CACHE_TIMEOUT, 600);
//执行连接
res = curl_easy_perform(curl);
/* Check for errors */
if(res != CURLE_OK)
{
fprintf(stderr, "PostVerifyCodeRequest() failed: %s\n", curl_easy_strerror(res));
}
//释放由curl_slist_append构建的curl_slist
//curl_slist_free_all(headers);
/* always cleanup */
curl_easy_cleanup(curl);
//字符集转换
std::wstring wstrResponse = wsc.from_bytes(strResponseUTF8);
typedef std::codecvt_byname<wchar_t, char, std::mbstate_t> cb;
static std::wstring_convert<cb> strCnv(new cb("Chinese"));
strResponse = strCnv.to_bytes(wstrResponse);
Document docResponse;
docResponse.Parse(strResponse.c_str());
TCHAR szMessage[256]=TEXT("");
if (docResponse.HasMember("code")==true)
{
Value& valError=docResponse["code"];
Value& valErrorMsg=docResponse["description"];
//错误信息
int ErrorCode = -1;
std::string strError = "";
std::string strErrorMsg = "";
if(valError.IsString()) strError = valError.GetString();
if(valErrorMsg.IsString()) strErrorMsg = valErrorMsg.GetString();
//结果判断
if(strError != std::string("000000"))
{
//输出错误
std::string strStatus;
if (docResponse.HasMember("result")==true)
{
Value& valData=docResponse["result"][0];
if (valData.HasMember("status")==true)
{
Value& valStatus=valData["status"];
if(valStatus.IsString()) strStatus = valStatus.GetString();
}
}
_sntprintf(szMessage,CountArray(szMessage),TEXT("短信发送失败 User %d message=%s code=%s status=%s"),
pUserVerifyCodeInfo->dwUserID, strCnv.from_bytes(strErrorMsg).c_str(),strCnv.from_bytes(strError).c_str(),strCnv.from_bytes(strStatus).c_str());
Log(LogLevel_Error, szMessage);
return 1;
}
else
{
Log(TraceLevel_Info, TEXT("短信发送成功【%s】:【%s】"), pUserVerifyCodeInfo->szMobile, pUserVerifyCodeInfo->szVerifyCode);
}
}
else
{
return 0;
}
}
return true;
}
//主要代码在上面,不保证能编译通过,但是关键代码都有,有些接口是从网上找的