PageRenderTime 26ms CodeModel.GetById 2ms app.highlight 16ms RepoModel.GetById 2ms app.codeStats 0ms

/BlogEngine/BlogEngine.NET/App_Code/Extensions/Recaptcha/RecaptchaValidator.cs

#
C# | 188 lines | 105 code | 32 blank | 51 comment | 13 complexity | 443a98ce4b75bfbcf8d2b21c6d59a8ed MD5 | raw file
  1// Copyright (c) 2007 Adrian Godong, Ben Maurer
  2// Permission is hereby granted, free of charge, to any person obtaining a copy
  3// of this software and associated documentation files (the "Software"), to deal
  4// in the Software without restriction, including without limitation the rights
  5// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  6// copies of the Software, and to permit persons to whom the Software is
  7// furnished to do so, subject to the following conditions:
  8// The above copyright notice and this permission notice shall be included in
  9// all copies or substantial portions of the Software.
 10// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 11// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 12// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 13// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 14// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 15// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 16// THE SOFTWARE.
 17
 18// Adapted for dotnetblogengine by Filip Stanek ( http://www.bloodforge.com )
 19
 20namespace Recaptcha
 21{
 22    using System;
 23    using System.IO;
 24    using System.Net;
 25    using System.Net.Sockets;
 26    using System.Text;
 27    using System.Web;
 28
 29    /// <summary>
 30    /// Calls the reCAPTCHA server to validate the answer to a reCAPTCHA challenge. Normally,
 31    ///     you will use the RecaptchaControl class to insert a web control on your page. However
 32    /// </summary>
 33    public class RecaptchaValidator
 34    {
 35        #region Constants and Fields
 36
 37        /// <summary>
 38        /// The verify url.
 39        /// </summary>
 40        private const string VerifyUrl = "http://api-verify.recaptcha.net/verify";
 41
 42        /// <summary>
 43        /// The remote ip.
 44        /// </summary>
 45        private string remoteIp;
 46
 47        #endregion
 48
 49        #region Properties
 50
 51        /// <summary>
 52        /// Gets or sets Challenge.
 53        /// </summary>
 54        public string Challenge { get; set; }
 55
 56        /// <summary>
 57        /// Gets or sets PrivateKey.
 58        /// </summary>
 59        public string PrivateKey { get; set; }
 60
 61        /// <summary>
 62        /// Gets or sets RemoteIP.
 63        /// </summary>
 64        /// <exception cref="ArgumentException">
 65        /// </exception>
 66        public string RemoteIP
 67        {
 68            get
 69            {
 70                return this.remoteIp;
 71            }
 72
 73            set
 74            {
 75                var ip = IPAddress.Parse(value);
 76
 77                if (ip.AddressFamily != AddressFamily.InterNetwork && ip.AddressFamily != AddressFamily.InterNetworkV6)
 78                {
 79                    throw new ArgumentException(string.Format("Expecting an IP address, got {0}", ip));
 80                }
 81
 82                this.remoteIp = ip.ToString();
 83            }
 84        }
 85
 86        /// <summary>
 87        /// Gets or sets Response.
 88        /// </summary>
 89        public string Response { get; set; }
 90
 91        #endregion
 92
 93        #region Public Methods
 94
 95        /// <summary>
 96        /// Validates this instance.
 97        /// </summary>
 98        /// <returns>The response.</returns>
 99        public RecaptchaResponse Validate()
100        {
101            CheckNotNull(this.PrivateKey, "PrivateKey");
102            CheckNotNull(this.RemoteIP, "RemoteIp");
103            CheckNotNull(this.Challenge, "Challenge");
104            CheckNotNull(this.Response, "Response");
105
106            if (this.Challenge == string.Empty || this.Response == string.Empty)
107            {
108                return RecaptchaResponse.InvalidSolution;
109            }
110
111            var request = (HttpWebRequest)WebRequest.Create(VerifyUrl);
112
113            // to avoid issues with Expect headers
114            request.ProtocolVersion = HttpVersion.Version10;
115            request.Timeout = 30 * 1000 /* 30 seconds */;
116            request.Method = "POST";
117            request.UserAgent = "reCAPTCHA/ASP.NET";
118
119            request.ContentType = "application/x-www-form-urlencoded";
120
121            var formdata = String.Format(
122                "privatekey={0}&remoteip={1}&challenge={2}&response={3}",
123                HttpUtility.UrlEncode(this.PrivateKey),
124                HttpUtility.UrlEncode(this.RemoteIP),
125                HttpUtility.UrlEncode(this.Challenge),
126                HttpUtility.UrlEncode(this.Response));
127
128            var formbytes = Encoding.ASCII.GetBytes(formdata);
129
130            using (var requestStream = request.GetRequestStream())
131            {
132                requestStream.Write(formbytes, 0, formbytes.Length);
133            }
134
135            string[] results;
136
137            try
138            {
139                using (var httpResponse = request.GetResponse())
140                {
141                    var httpResponseStream = httpResponse.GetResponseStream();
142                    if (httpResponseStream == null)
143                    {
144                        return RecaptchaResponse.RecaptchaNotReachable;
145                    }
146
147                    using (TextReader readStream = new StreamReader(httpResponseStream, Encoding.UTF8))
148                    {
149                        results = readStream.ReadToEnd().Split();
150                    }
151                }
152            }
153            catch (WebException)
154            {
155                return RecaptchaResponse.RecaptchaNotReachable;
156            }
157
158            switch (results[0])
159            {
160                case "true":
161                    return RecaptchaResponse.Valid;
162                case "false":
163                    return new RecaptchaResponse(false, results[1]);
164                default:
165                    throw new InvalidProgramException("Unknown status response.");
166            }
167        }
168
169        #endregion
170
171        #region Methods
172
173        /// <summary>
174        /// Checks the not null.
175        /// </summary>
176        /// <param name="obj">The object to check.</param>
177        /// <param name="name">The object name.</param>
178        private static void CheckNotNull(object obj, string name)
179        {
180            if (obj == null)
181            {
182                throw new ArgumentNullException(name);
183            }
184        }
185
186        #endregion
187    }
188}