블로그 이미지
래머
오늘도 열심히 개발하는 개발자입니다.

calendar

1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31

Notice

2014. 5. 3. 23:52 iOS


유니티에서 사용하고자 하는경우 아래 코드를 추가하시고
InitCertificateValidationCallback()을 영수증 검증 루틴 실행전 한번 호출해줄필요가 있습니다.

public static void InitCertificateValidationCallback()
        {
            ServicePointManager.ServerCertificateValidationCallback += new System.Net.Security.RemoteCertificateValidationCallback(ValidateServerCertificate);
        }

        static bool ValidateServerCertificate(object sender, System.Security.Cryptography.X509Certificates.X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
        {
            return true;
        }

iOS인앱 결제 후 영수증 검증 루틴이다.

첨부된 JSON라이브러리를 c#프로젝트의 참조에 추가할 필요가 있다.

VerifyIOSReceipt 메소드의 리턴값을 판별해서 

처리하면된다.


IOS_RV_SUCCESS = 영수증 검증 성공

IOS_RV_FAIL_RETRY  = 영수증 검증에 실패 했다, 샌드박스모드에서 다시 검증이 필요하다.

IOS_RV_FAIL  = 유효하지 않은 영수증이다.


using System.Text;

using System.Net;

using System.IO;

using Newtonsoft.Json;

using Newtonsoft.Json.Linq;

using System;


public class CIOSReceiptVerificationMng

{

    public const string IOS_PRODUCT_URL = "https://buy.itunes.apple.com/verifyReceipt";

    public const string IOS_SENDBOX_URL = "https://sandbox.itunes.apple.com/verifyReceipt";


    public const int IOS_RV_SUCCESS = 0;    //ios영수증 검증 결과 성공

    public const int IOS_RV_FAIL_RETRY = 1;    //샌드박스에서 재검증필요

    public const int IOS_RV_FAIL = -1;    //검증 실패


    /*ios영수증 검증

itemID = 해당 영수증으로 결제한 아이템의 ID

receiptData = 영수증 데이터

bProduct = 프로덕트에서 검증할지 샌드박스에서 검증할지, 기본적으로 프로덕트에서 검증하고 리턴값이 IOS_RV_FAIL_RETRY  인경우에 샌드박스에서 검증한다.

*/

    public static int VerifyIOSReceipt(ref string itemID, string receiptData, bool bProduct)

    {

        try

        {

            itemID = null;


            // Verify the receipt with Apple

            string postString = string.Format("{{ \"receipt-data\" : \"{0}\" }}", receiptData);

            ASCIIEncoding ascii = new ASCIIEncoding();

            byte[] postBytes = ascii.GetBytes(postString);

            HttpWebRequest request;


            if (bProduct)

                request = WebRequest.Create(IOS_PRODUCT_URL) as HttpWebRequest;

            else

                request = WebRequest.Create(IOS_SENDBOX_URL) as HttpWebRequest;


            request.Method = "POST";

            request.ContentType = "application/json";

            request.ContentLength = postBytes.Length;

            Stream postStream = request.GetRequestStream();

            postStream.Write(postBytes, 0, postBytes.Length);

            postStream.Close();


            HttpWebResponse response = request.GetResponse() as HttpWebResponse;

            StringBuilder sb = new StringBuilder();

            byte[] buf = new byte[8192];

            Stream resStream = response.GetResponseStream();

            string tempString = null;


            int count = 0;


            do

            {

                count = resStream.Read(buf, 0, buf.Length);

                if (count != 0)

                {

                    tempString = Encoding.ASCII.GetString(buf, 0, count);

                    sb.Append(tempString);

                }

            } while (count > 0);


            var fd = JObject.Parse(sb.ToString());


            try

            {

                resStream.Close();

                response.Close();

            }

            catch

            {

            }


            string strResult = fd["status"].ToString();

            // Receipt not valid

            if (strResult != "0")

            {

                if (strResult == "21007")

                    return IOS_RV_FAIL_RETRY;


                // Error out

                return IOS_RV_FAIL;

            }


            // Product ID does not match what we expected

            var receipt = fd["receipt"];


            /*

            if (String.Compare(receipt["product_id"].ToString().Replace("\"", "").Trim(), itemID.Trim(), true) != 0)

            {

                // Error out

                return IOS_RV_FAIL;

            }

             * */


            //제품 ID정보를 저장함

            itemID = receipt["product_id"].ToString().Replace("\"", "").Trim();


            // This product was not sold by the right app

            if (String.Compare(receipt["bid"].ToString().Replace("\"", "").Trim(), PACKAGE_NAME, true) != 0)

            {

                // Error out

                return IOS_RV_FAIL;

            }


            /*

            // This transaction didn't occur within 24 hours in either direction; somebody is reusing a receipt

            DateTime transDate = DateTime.SpecifyKind(DateTime.Parse(receipt["purchase_date"].ToString().Replace("\"", "").Replace("Etc/GMT", "")), DateTimeKind.Utc);

            TimeSpan delay = DateTime.UtcNow - transDate;

            if (delay.TotalHours > 24 || delay.TotalHours < -24)

            {

                // Error out

                return false;

            }

            */


            // Perform the purchase -- all my purchases are server-side only, which is a very secure way of doing things

            // Success!

        }

        catch// (Exception ex)

        {

            // We crashed and burned -- do something intelligent

            return IOS_RV_FAIL;

        }


        return IOS_RV_SUCCESS;

    }


}


Newtonsoft.Json.dll


Newtonsoft.Json.xml





'iOS' 카테고리의 다른 글

앱스토어 가이드라인  (0) 2015.10.10
iOS사파리 브라우져를 열어서 특정 사이트로 이동  (0) 2014.05.05
posted by 래머
2014. 5. 3. 23:43 안드로이드

첨부된 바운시캐슬 암호화 라이브러리를 참조에 추가하고 사용해야 한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
using System;
 
using System.Security.Cryptography;
 
using System.IO;
 
using System.Text;
 
using System.Xml;
 
using System.Collections.Generic;
 
using System.Linq;
 
using Org.BouncyCastle.Security;
 
using Org.BouncyCastle.Crypto;
 
using Org.BouncyCastle.Crypto.Parameters;
 
 
 
 
/*
사용법
GoogleSignatureVerify gsv = new GoogleSignatureVerify("발급받은 API키");
if (gsv.Verify("결제데이터", 사인데이터))
{
//성공시 처리
}
*/
 
public class GoogleSignatureVerify
 
    {
 
        RSAParameters _rsaKeyInfo;
 
 
 
 
        public GoogleSignatureVerify(String GooglePublicKey)
 
        {
 
            RsaKeyParameters rsaParameters = (RsaKeyParameters)PublicKeyFactory.CreateKey(Convert.FromBase64String(GooglePublicKey));
 
 
 
 
            byte[] rsaExp = rsaParameters.Exponent.ToByteArray();
 
            byte[] Modulus = rsaParameters.Modulus.ToByteArray();
 
 
 
 
            // Microsoft RSAParameters modulo wants leading zero's removed so create new array with leading zero's removed
 
            int Pos = 0;
 
            for (int i = 0; i < Modulus.Length; i++)
 
            {
 
                if (Modulus[i] == 0)
 
                {
 
                    Pos++;
 
                }
 
                else
 
                {
 
                    break;
 
                }
 
            }
 
            byte[] rsaMod = new byte[Modulus.Length - Pos];
 
            Array.Copy(Modulus, Pos, rsaMod, 0, Modulus.Length - Pos);
 
 
 
 
            // Fill the Microsoft parameters
 
            _rsaKeyInfo = new RSAParameters()
 
            {
 
                Exponent = rsaExp,
 
                Modulus = rsaMod
 
            };
 
        }
 
 
 
 
        public bool Verify(String Message, String Signature)
 
        {
 
            using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
 
            {
 
                rsa.ImportParameters(_rsaKeyInfo);
 
                return rsa.VerifyData(Encoding.ASCII.GetBytes(Message), "SHA1", Convert.FromBase64String(Signature));
 
            }
 
        }
 
    }
 
 
 
cs

BouncyCastle.Crypto.dll

유니티를 사용하신다면 아래 유니티 패키지를 임포트 하시면 바운시 캐슬 라이브러리소스가 임포트됩니다.


BouncyCastle.unitypackage



posted by 래머
2014. 5. 3. 23:11 안드로이드
유니티에서 사용하고자 하는경우 아래 코드를 추가하시고
InitCertificateValidationCallback()을 영수증 검증 루틴 실행전 한번 호출해줄필요가 있습니다.

public static void InitCertificateValidationCallback()
        {
            ServicePointManager.ServerCertificateValidationCallback += new System.Net.Security.RemoteCertificateValidationCallback(ValidateServerCertificate);
        }

        static bool ValidateServerCertificate(object sender, System.Security.Cryptography.X509Certificates.X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
        {
            return true;
        }

c#으로 작성된 서버 또는 유니티 등에서 티스토어의 인앱 결제 영수증 검증을 다음과 같이 하면된다.



readonly string TSTORE_RECEIPT_VERIFY_URL_PRODUCT = "https://iap.tstore.co.kr/digitalsignconfirm.iap";  //실서비스용서버주소

        readonly string TSTORE_RECEIPT_VERIFY_URL_DEV = "https://iapdev.tstore.co.kr/digitalsignconfirm.iap"; //개발용서버주소

        readonly string TSTORE_RECEIPT_VERIFY_FORMAT = "{{\"txid\" : \"{0}\", \"appid\" : \"{1}\", \"signdata\" : \"{2}\"}}";

        //TStore 영수증 검중구현, 

//bProduct : 서비스/개발용 서버중 어느 서버에서 검증할지

//strAppID : 티스토어에 배포한 프로그램에 할당받은 ID

//strTXID : 인앱 결제후 결과 값으로 넘어온 것중 txid

//strReceipt : 인앱결제 후 결과 값으로 넘어온 영수증 정보

//리턴값이 true인경우 영수증검증에 성공한것이다.

//애플의 영수증을 검증하는 것처럼 먼저 bProduct에 true를 해서 영수증검증을 해보고 만일 실패 하는경우

//false를 줘서 검증을 시도하도록 하면 된다.

        bool VerifyTStoreReceipt(bool bProduct, string strAppID, string strTXID, string strReceipt)

        {

            try

            {

                // Verify the receipt with Apple

                string postString = String.Format(TSTORE_RECEIPT_VERIFY_FORMAT, strTXID, strAppID, strReceipt);

                ASCIIEncoding ascii = new ASCIIEncoding();

                byte[] postBytes = ascii.GetBytes(postString);

                HttpWebRequest request;


                if (bProduct)

                    request = WebRequest.Create(TSTORE_RECEIPT_VERIFY_URL_PRODUCT) as HttpWebRequest;

                else

                    request = WebRequest.Create(TSTORE_RECEIPT_VERIFY_URL_DEV) as HttpWebRequest;


                request.Method = "POST";

                request.ContentType = "application/json";

                request.ContentLength = postBytes.Length;

                Stream postStream = request.GetRequestStream();

                postStream.Write(postBytes, 0, postBytes.Length);

                postStream.Close();


                HttpWebResponse response = request.GetResponse() as HttpWebResponse;

                StringBuilder sb = new StringBuilder();

                byte[] buf = new byte[8192];

                Stream resStream = response.GetResponseStream();

                string tempString = null;


                int count = 0;


                do

                {

                    count = resStream.Read(buf, 0, buf.Length);

                    if (count != 0)

                    {

                        tempString = Encoding.ASCII.GetString(buf, 0, count);

                        sb.Append(tempString);

                    }

                } while (count > 0);


                var fd = JObject.Parse(sb.ToString());


                try

                {

                    resStream.Close();

                    response.Close();

                }

                catch

                {

                }


                string strResult = fd["status"].ToString();

                string strDetail = fd["detail"].ToString();


                // Receipt not valid

                if (strResult == null || strResult != "0" || strDetail == null || strDetail != "0000")

                {

#if DEBUG

                    CLogMng.Instance().Debug("tstore purchase failed : " + sb.ToString());

                    CLogMng.Instance().Debug("txid : " + strTXID);

                    CLogMng.Instance().Debug("signdata : " + strReceipt);

#endif

                    return false;

                }

            }

            catch// (Exception ex)

            {

                // We crashed and burned -- do something intelligent

                return false;

            }


            return true;

        }




posted by 래머
prev 1 next