Native/C++

me2day

aucd29 2013. 10. 2. 19:06
- 주로 브라우저가 없는 곳에서 작업을 해야 되는 상태라 다음과 같이 HTTP Authentication: Basic 를 이용해서 접근 하는 방법으로 구현 한다.
- me2day 가 xauth를 지원하면 좋겠다만은.. 없는 것 같으니 일단 이걸로 ..
- me2day api 사이트 http://dev.naver.com/openapi/apis/me2day/me2api_intro#metwo3
- LOG 는 printf 로 대체 된다.
- HTTP 전송은 libcurl 을 이용했다.
- md5 는 openssl 을 이용했다. (md5만 오픈되어 있는 것 많으니 굳이 openssl 을 사용하지 않아도 된다.)

[code]
/**
* @file CMe2day.h
* @author cheol-dong choi <aucd29@gmail.com>
* @version 1.0
* @date 2011-01-05 (10:07:00)
* @section LICENSE
*
* Copyright (c) 2003-2011, cheol-dong choi, (http://www.sarangnamu.net)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* @section DESCRIPTION
*
* - 애플리케이션 키는 http://me2day.net/api/front/appkey 에서 로그인 후 받는다.
* 이는 파라메터로 넘기거나 HTTP 헤더에 다음과 같이 넣을 수 있다.
*
* @code
* ME2DAY-API-APPKEY: $(your app key)
* @endcode
*
* - 사용자(유저) 키는 로그인 후 다음의 경로에서 받는다.
*
* @code
* me2day.net/$(your id)/setting
* @endcode
*
* - nonce 는 임의의 8 자리 문자열을 직접 생성한다 api 설명에는 왜 저렇게 말을
* 어렵게 적어놓은건지 모르겠다... 내가 난독증인건가?
*
* @code
* 인증키는 8자리 nonce 문자열과 사용자 키를 붙인 후 md5로 인코딩하고 앞에
* 다시 nonce 문자열을 붙여 만들어진 문자열입니다. 여기서 nonce는
* me2API 어플리케이션 측에서 임의로 생성된 8자리 16진수 문자열입니다.
* @endcode
*
* 위와 같이 적혀 있어서me2API 에 nonce 값을 리턴해주는 api가 있는지 찾아댕긴.
*
*
* @see RFC-2617 http://sarangnamu.net/basic/basic_view.php?no=4569&page=1&sCategory=0
* @see Me2day open api http://dev.naver.com/openapi/apis/me2day/me2api_intro#metwo3
*
* - sample code
* @code
*        CMe2day me2day;
*        me2day.setUserID("aucd29");
*        me2day.setAppKey("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
*        me2day.setUserKey("12345678");
*        me2day.sendHTTPBasicAuth();
* @endcode
*
* @section CHANGE_LOG
*
*/

#ifndef __CD_CME2DAY_H__
#define __CD_CME2DAY_H__


#include <string>


#define ME2DAY_GET_TOKEN "http://me2day.net/api/get_auth_url"
#define ME2DAY_GET_NOOP "http://me2day.net/api/noop"


/**
* @class CMe2day
* @brief
*/
class CMe2day
{
public:

    /*
     * Construction
     */
    CMe2day();

    /*
     * Destructor
     */
    virtual ~CMe2day();

public:

    /*
     * Getter methods
     */
    void setUserID(const char* userID);

    void setUserKey(const char* userkey);

    void setAppKey(const char* appKey);

    int sendHTTPBasicAuth();


protected:

    /*
     * Internal methods
     */
    std::string getNonce();

    std::string getAuthKey();

    std::string getMe2dayAppKey();

    std::string getHttpBasicAuth();

protected:

    /*
     * Attributes
     */
    std::string _userID;

    std::string _userKey;

    std::string _appKey;

};

#endif
[/code]

[code]
/**
* @file CMe2day.cpp
* @author cheol-dong choi <aucd29@gmail.com>
* @version 1.0
* @date 2011-01-05 (10:07:06)
* @section LICENSE
*
* Copyright (c) 2003-2011, cheol-dong choi, (http://www.sarangnamu.net)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* @section DESCRIPTION
*
*
* @section CHANGE_LOG
*
*/

#include "CMe2day.h"
#include "RSLOGGER.H"
#include <time.h>
#include <math.h>
#include "base64.h"
#include "CMD5Manager.h"
#include "CCURLManager.h"


/*
* Constructor CMe2day
*/
CMe2day::CMe2day()
{
    LOG1("CMe2day::CMe2day\n");

}


/*
* Destructor ~CMe2day
*/
CMe2day::~CMe2day()
{
    LOG1("CMe2day::~CMe2day\n");

}


/**
* 사용자 유저 아이디를 설정 한다. (네이버 아이디 같은..)
*
* @param userID 사용자 아이디
*/
void CMe2day::setUserID(const char* userID)
{
    LOG1("CMe2day::setUserID\n");

    _userID = userID;
}


/**
* 유저 아이디를 설정 한다.
*
* @param userkey 유저 아이디
*/
void CMe2day::setUserKey(const char* userkey)
{
    LOG1("CMe2day::setUserKey\n");
    LOG2("set user key value : %s", userkey);

    _userKey = userkey;
}


/**
* 어플리케이션 아이디를 설정 한다.
*
* @param appKey 어플리케이션 아이디
*/
void CMe2day::setAppKey(const char* appKey)
{
    LOG1("CMe2day::setAppKey\n");
    LOG2("set app key value : %s\n", appKey);

    _appKey = appKey;
}


/**
* HTTP Authentication: Basic 를 시도 한다.
*
* @return true or false
*/
int CMe2day::sendHTTPBasicAuth()
{
    LOG1("CMe2day::sendHTTPBasicAuth\n");

    int res;
    CCURLManager curl;
    FILE* head = NULL, * body = NULL;
    std::string httpHeader, appKey, httpAuth;

    appKey = getMe2dayAppKey();
    if (appKey.size() == 0)
    {
        return false;
    }

    httpAuth = getHttpBasicAuth();
    if (httpAuth.size() == 0)
    {
        return false;
    }

    httpHeader = appKey;
    httpHeader += "\r\n";
    httpHeader += httpAuth;

    curl.SetCustomHeader(httpHeader.c_str());
    res = curl.CurlCommon(head, body, ME2DAY_GET_NOOP, NULL, CURL_COMMON_MEM_WRITE);
    if (res != CURLE_OK)
    {
        return false;
    }

    LOG2("response body : %s\n", curl.GetMemoryBody().c_str());

    return true;
}


/**
* 임의의 8자리 문자열을 만든다.
*
* @return nonce 문자열
*/
std::string CMe2day::getNonce()
{
    LOG1("CMe2day::getNonce\n");

    std::string nonce;
    std::string seed = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";

    srand((unsigned int)(time(NULL)));

    for(size_t i=0;i<8; ++i)
    {
        nonce += seed[ rand() % seed.size() ];
    }

    LOG2("generated nonce value : %s", nonce.c_str());

    return nonce;
}


/**
* me2day openapi 에 해당하는 auth key를 생성한다.
*
* @return auth key
*/
std::string CMe2day::getAuthKey()
{
    LOG1("CMe2day::getAuthKey\n");

    std::string authKey;
    std::string nonce;

    nonce    = getNonce();
    authKey = nonce;
    authKey += CMD5::toMD5((nonce + _userKey).c_str());

    return authKey;
}


/**
* http 헤더에 포함될 어플리케이션 키를 만든다.
*
* @return http 헤더 포맷에 어플리케이션 키
*/
std::string CMe2day::getMe2dayAppKey()
{
    LOG1("CMe2day::getMe2dayAppKey\n");

    if (_appKey.size() == 0)
    {
        LOG2("invalid app key\n");
        return "";
    }

    return "ME2DAY-API-APPKEY: " + _appKey;
}


/**
* HTTP Authentication: Basic 에 해당하는 문자열을 생성 한다.
*
* @return HTTP Authentication: Basic 데이터
*/
std::string CMe2day::getHttpBasicAuth()
{
    LOG1("CMe2day::getHttpBasicAuth\n");

    if (_userID.size() == 0)
    {
        LOG3("CMe2day::getHttpBasicAuth <invalid user id>\n");
        return "";
    }

    std::string auth;
    bool res = false;
    char* base64 = NULL;
    
    // RFC 2617 - HTTP Authentication: Basic and Digest Access Authentication
    auth = _userID;
    auth += ":";
    auth += getAuthKey();

    base64 = base64_encode(auth.size(), (unsigned char*)auth.c_str());
    if (base64 == NULL)
    {
        LOG3("CMe2day::getHttpBasicAuth <base64 == NULL>\n");
        return "";
    }

    auth = "Authorization: Basic ";
    auth += base64;
    free(base64);
    LOG2("http basic auth value : %s\n", auth.c_str());

    return auth;
}
[/code]