// demoLoginByAppIdDlg.cpp : 实现文件
//

#include "stdafx.h"
#include "demo.h"
#include "demoLoginByAppIdDlg.h"
#include "afxdialogex.h"
#include "demoTools.h"
#include "openssl/rand.h"
#include "openssl/hmac.h"
#include "HwmSdkAgent.h"
#include <sstream>
#include <iostream>

#define SHA256_DIGEST_LENGTH   32

// demoLoginByAppIdDlg 对话框

IMPLEMENT_DYNAMIC(demoLoginByAppIdDlg, CDialogEx)

demoLoginByAppIdDlg::demoLoginByAppIdDlg(CWnd* pParent /*=NULL*/)
	: CDialogEx(IDD_LOGIN_BY_APP_ID_DIALOG, pParent)
{

}

demoLoginByAppIdDlg::~demoLoginByAppIdDlg()
{
}

void demoLoginByAppIdDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
    DDX_Control(pDX, IDC_EDIT_APP_KEY, m_appKeyEdit);
    DDX_Control(pDX, IDC_EDIT_CORP_ID, m_corpIdEdit);
    DDX_Control(pDX, IDC_EDIT_USER_ID, m_userIdEdit);
    DDX_Control(pDX, IDC_EDIT_USER_NAME, m_userNameEdit);
    DDX_Control(pDX, IDC_EDIT_EMAIL, m_emailEdit);
    DDX_Control(pDX, IDC_EDIT_PHONE_NUM, m_phoneNumEdit);
    DDX_Control(pDX, IDC_EDIT_TIME, m_expireTimeEdit);
    DDX_Control(pDX, IDC_EDIT_DEPT_CODE, m_deptCode);
}


BEGIN_MESSAGE_MAP(demoLoginByAppIdDlg, CDialogEx)
    ON_BN_CLICKED(IDC_BUTTON_LOGIN_BY_APP_ID_OK, &demoLoginByAppIdDlg::OnBnClickedButtonOk)
END_MESSAGE_MAP()


// demoLoginByAppIdDlg 消息处理程序

BOOL demoLoginByAppIdDlg::OnInitDialog()
{
    CDialogEx::OnInitDialog();

    // 从配置文件读取上次登录信息
    CString temp = _T("");
    CTools::getIniConfigParam(_T("LoginConfig"), _T("appKey"), temp);
    m_appKeyEdit.SetWindowText(temp);
    CTools::getIniConfigParam(_T("LoginConfig"), _T("corpId"), temp);
    m_corpIdEdit.SetWindowText(temp);
    CTools::getIniConfigParam(_T("LoginConfig"), _T("userId"), temp);
    m_userIdEdit.SetWindowText(temp);
    CTools::getIniConfigParam(_T("LoginConfig"), _T("userName"), temp);
    m_userNameEdit.SetWindowText(temp);
    CTools::getIniConfigParam(_T("LoginConfig"), _T("email"), temp);
    m_emailEdit.SetWindowText(temp);
    CTools::getIniConfigParam(_T("LoginConfig"), _T("phone"), temp);
    m_phoneNumEdit.SetWindowText(temp);
    CTools::getIniConfigParam(_T("LoginConfig"), _T("expireTime"), temp);
    m_expireTimeEdit.SetWindowText(temp);
    CTools::getIniConfigParam(_T("LoginConfig"), _T("deptCode"), temp);
    m_deptCode.SetWindowText(temp);

    return TRUE;  // 除非将焦点设置到控件，否则返回 TRUE
}

//获取定长随机字符串
void demoLoginByAppIdDlg::GetRandStr(char *str, const int len)
{
    unsigned int i;
    for (i = 0; i < (len - 1); ++i) {
        //获取类型随机数
        unsigned char nonce = 0;
        RAND_bytes(&nonce, 1);
        unsigned int randType = static_cast<unsigned int>(nonce);
        //获取字符随机数
        RAND_bytes(&nonce, 1);
        unsigned int randNum = static_cast<unsigned int>(nonce);
        switch ((randType % 3)) {
            case 1: {
                str[i] = 'A' + randNum % 26;
                break;
            }
            case 2: {
                str[i] = 'a' + randNum % 26;
                break;
            }
            default: {
                str[i] = '0' + randNum % 10;
                break;
            }
        }
    }
    str[i] = '\0';
}

void demoLoginByAppIdDlg::OnBnClickedButtonOk()
{
    //获取初始化的AppId信息
    CString appIdCstr;
    CTools::getIniConfigParam(_T("LoginConfig"), _T("appId"), appIdCstr);
    string appId = CTools::UNICODE2UTF(appIdCstr.GetString());
    //获取界面填入的信息
    CString appKeyCstr;
    m_appKeyEdit.GetWindowText(appKeyCstr);
    string appKey = CTools::UNICODE2UTF(appKeyCstr.GetString());
    CString corpIdCstr;
    m_corpIdEdit.GetWindowText(corpIdCstr);
    string corpId = CTools::UNICODE2UTF(corpIdCstr.GetString());

    CString userIdCstr;
    m_userIdEdit.GetWindowText(userIdCstr);
    string userId = CTools::UNICODE2UTF(userIdCstr.GetString());

    CString userNameCstr;
    m_userNameEdit.GetWindowText(userNameCstr);
    string userName = CTools::UNICODE2UTF(userNameCstr.GetString());

    CString emailCstr;
    m_emailEdit.GetWindowText(emailCstr);
    string email = CTools::UNICODE2UTF(emailCstr.GetString());

    CString phoneNumCstr;
    m_phoneNumEdit.GetWindowText(phoneNumCstr);
    string phoneNumber = CTools::UNICODE2UTF(phoneNumCstr.GetString());

    CString expireTimeCstr;
    m_expireTimeEdit.GetWindowText(expireTimeCstr);
    long long expireTime = _ttoi(expireTimeCstr);
    if (expireTime != 0) {
        expireTime = time(NULL) + expireTime;
    }
    string expireTimeStr = CTools::LL2S(expireTime);

    CString deptCodeCstr;
    m_deptCode.GetWindowText(deptCodeCstr);
    string deptCode = CTools::UNICODE2UTF(deptCodeCstr.GetString());

    //获取随机数
    char nonce[HWM_APPID_NONCE_LEN] = { 0 };
    GetRandStr(nonce, HWM_APPID_NONCE_LEN);
    nonce[HWM_APPID_NONCE_LEN - 1] = '\0';
    //组装输入数据
    string input;
    if (corpId.empty()) // corpId为空时不使用corpId计算签名
    {
        input = appId + ":" + userId + ":" + expireTimeStr + ":" + nonce;
    }
    else
    {
        input = appId + ":" + corpId + ":" + userId + ":" + expireTimeStr + ":" + nonce;
    }
    //指定算法
    const EVP_MD * engine = EVP_sha256();
    unsigned int outputLength = SHA256_DIGEST_LENGTH;
    unsigned char output[SHA256_DIGEST_LENGTH] = { 0 };

    string signature = "";
    if (appKey.length() != 0) {
        //初始化资源
        HMAC_CTX *ctx = HMAC_CTX_new();
        if (ctx != NULL) {
            HMAC_CTX_reset(ctx);
            //计算数据
            HMAC_Init_ex(ctx, appKey.c_str(), appKey.length(), engine, NULL);
            HMAC_Update(ctx, (unsigned char*)input.c_str(), input.length());
            HMAC_Final(ctx, output, &outputLength);
            //释放资源
            HMAC_CTX_free(ctx);
            vector<unsigned char> vec(output, output + outputLength);
            signature = CTools::Hex2Str(vec);
        }
    }

    //组装入参结构体
    hwmsdkagent::HwmLoginInfo loginParam;
    memset(&loginParam, 0, sizeof(hwmsdkagent::HwmLoginInfo));
    loginParam.authType = hwmsdkagent::HWM_AUTH_TYPE_APPID;
    //检查输入长度
    if ((userId.length() + 1 > sizeof(loginParam.appIdAuthInfo.thirdUserId))
        || (corpId.length() + 1 > sizeof(loginParam.appIdAuthInfo.corpId))
        || (userName.length() + 1 > sizeof(loginParam.appIdAuthInfo.userName))
        || (signature.length() + 1 > sizeof(loginParam.appIdAuthInfo.signature))
        || (email.length() + 1 > sizeof(loginParam.appIdAuthInfo.email))
        || (phoneNumber.length() + 1 > sizeof(loginParam.appIdAuthInfo.phoneNumber))
        || (deptCode.length() + 1 > sizeof(loginParam.appIdAuthInfo.deptCode))){
        AfxMessageBox(_T("param length over limit"));
        return;
    }
    errno_t err = strcpy_s(loginParam.appIdAuthInfo.corpId, sizeof(loginParam.appIdAuthInfo.corpId), corpId.c_str());
    err += strcpy_s(loginParam.appIdAuthInfo.thirdUserId, sizeof(loginParam.appIdAuthInfo.thirdUserId), userId.c_str());
    err += strcpy_s(loginParam.appIdAuthInfo.userName, sizeof(loginParam.appIdAuthInfo.userName), userName.c_str());
    err += strcpy_s(loginParam.appIdAuthInfo.signature, sizeof(loginParam.appIdAuthInfo.signature), signature.c_str());
    err += strcpy_s(loginParam.appIdAuthInfo.nonce, sizeof(loginParam.appIdAuthInfo.nonce), nonce);
    err += strcpy_s(loginParam.appIdAuthInfo.email, sizeof(loginParam.appIdAuthInfo.email), email.c_str());
    err += strcpy_s(loginParam.appIdAuthInfo.phoneNumber, sizeof(loginParam.appIdAuthInfo.phoneNumber), phoneNumber.c_str());
    err += strcpy_s(loginParam.appIdAuthInfo.deptCode, sizeof(loginParam.appIdAuthInfo.deptCode), deptCode.c_str());
    if (err != S_OK)
    {
        AfxMessageBox(_T("String Copy Error!"));
    }

    loginParam.appIdAuthInfo.expireTime = expireTime;

    int ret = hwmsdkagent::Login(&loginParam);
    if (hwmsdk::HWM_COMMON_SUCCESS != ret) {
        CTools::OutputRetStr("Login error");
    }
    else {
        //登录接口调用成功后将登录信息保存到配置文件，下次启动读取
        CTools::writeIniConfigParam(_T("LoginConfig"), _T("appKey"), appKeyCstr);
        CTools::writeIniConfigParam(_T("LoginConfig"), _T("corpId"), corpIdCstr);
        CTools::writeIniConfigParam(_T("LoginConfig"), _T("userId"), userIdCstr);
        CTools::writeIniConfigParam(_T("LoginConfig"), _T("userName"), userNameCstr);
        CTools::writeIniConfigParam(_T("LoginConfig"), _T("email"), emailCstr);
        CTools::writeIniConfigParam(_T("LoginConfig"), _T("phone"), phoneNumCstr);
        CTools::writeIniConfigParam(_T("LoginConfig"), _T("expireTime"), expireTimeCstr);
        CTools::writeIniConfigParam(_T("LoginConfig"), _T("deptCode"), deptCodeCstr);
        //关闭当前窗口
        OnOK();
    }
    appKey.assign(appKey.length(), '\0');
    int len = appKeyCstr.GetLength();
    for (int idx = 0; idx < len; ++idx)
    {
        appKeyCstr.SetAt(idx, 0);
    }
}
