OSDN Git Service

OAuth署名生成などの処理をOAuthUtilityクラスに移動
authorKimura Youichi <kim.upsilon@bucyou.net>
Wed, 5 Aug 2015 11:25:31 +0000 (20:25 +0900)
committerKimura Youichi <kim.upsilon@bucyou.net>
Sat, 8 Aug 2015 12:19:51 +0000 (21:19 +0900)
OpenTween/Connection/HttpConnectionOAuth.cs
OpenTween/Connection/HttpConnectionOAuthEcho.cs
OpenTween/Connection/HttpOAuthApiProxy.cs
OpenTween/Connection/OAuthUtility.cs [new file with mode: 0644]
OpenTween/OpenTween.csproj

index 2861ef1..a5331b4 100644 (file)
@@ -26,6 +26,7 @@
 
 using HttpConnection = OpenTween.HttpConnection;
 using IHttpConnection = OpenTween.IHttpConnection;
+using OAuthUtility = OpenTween.Connection.OAuthUtility;
 using DateTime = System.DateTime;
 using DateTimeKind = System.DateTimeKind;
 using Random = System.Random;
@@ -85,7 +86,7 @@ namespace OpenTween
                /// <summary>
                /// OAuthのコンシューマー鍵
                /// </summary>
-               private string consumerKey;
+               protected string consumerKey;
 
                /// <summary>
                /// OAuthの署名作成用秘密コンシューマーデータ
@@ -486,69 +487,10 @@ namespace OpenTween
                /// <param name="tokenSecret">アクセストークンシークレット。認証処理では空文字列</param>
                protected virtual void AppendOAuthInfo( HttpWebRequest webRequest, Dictionary< string, string > query, string token, string tokenSecret )
                {
-                       // OAuth共通情報取得
-                       Dictionary< string, string > parameter = this.GetOAuthParameter( token );
-                       // OAuth共通情報にquery情報を追加
-                       if ( query != null )
-                               foreach ( KeyValuePair< string, string > item in query )
-                                       parameter.Add( item.Key, item.Value );
-                       // 署名の作成・追加
-                       parameter.Add( "oauth_signature", this.CreateSignature( tokenSecret, webRequest.Method, webRequest.RequestUri, parameter ) );
-                       // HTTPリクエストのヘッダに追加
-                       StringBuilder sb = new StringBuilder( "OAuth " );
-                       foreach ( KeyValuePair< string, string > item in parameter )
-                               // 各種情報のうち、oauth_で始まる情報のみ、ヘッダに追加する。各情報はカンマ区切り、データはダブルクォーテーションで括る
-                               if ( item.Key.StartsWith("oauth_") )
-                                       sb.AppendFormat( "{0}=\"{1}\",", item.Key, MyCommon.UrlEncode( item.Value ) );
-                       webRequest.Headers.Add( HttpRequestHeader.Authorization, sb.ToString() );
-               }
+                       var credential = OAuthUtility.CreateAuthorization( webRequest.Method, webRequest.RequestUri, query,
+                               this.consumerKey, this.consumerSecret, token, tokenSecret );
 
-               /// <summary>
-               /// OAuthで使用する共通情報を取得する
-               /// </summary>
-               /// <param name="token">アクセストークン、もしくはリクエストトークン。未取得なら空文字列</param>
-               /// <returns>OAuth情報のディクショナリ</returns>
-               protected Dictionary< string, string > GetOAuthParameter( string token )
-               {
-                       Dictionary< string, string > parameter = new Dictionary< string, string >();
-                       parameter.Add( "oauth_consumer_key", this.consumerKey );
-                       parameter.Add( "oauth_signature_method", "HMAC-SHA1" );
-                       parameter.Add( "oauth_timestamp", Convert.ToInt64( ( DateTime.UtcNow - HttpConnectionOAuth.UnixEpoch ).TotalSeconds ).ToString() ); // epoch秒
-                       parameter.Add( "oauth_nonce", HttpConnectionOAuth.NonceRandom.Next( 123400, 9999999 ).ToString() );
-                       parameter.Add( "oauth_version", "1.0" );
-                       if ( !string.IsNullOrEmpty( token ) )
-                               parameter.Add( "oauth_token", token ); // トークンがあれば追加
-                       return parameter;
-               }
-
-               /// <summary>
-               /// OAuth認証ヘッダの署名作成
-               /// </summary>
-               /// <param name="tokenSecret">アクセストークン秘密鍵</param>
-               /// <param name="method">HTTPメソッド文字列</param>
-               /// <param name="uri">アクセス先Uri</param>
-               /// <param name="parameter">クエリ、もしくはPOSTデータ</param>
-               /// <returns>署名文字列</returns>
-               protected virtual string CreateSignature( string tokenSecret, string method, Uri uri, Dictionary< string, string > parameter )
-               {
-                       // パラメタをソート済みディクショナリに詰替(OAuthの仕様)
-                       SortedDictionary< string, string > sorted = new SortedDictionary< string, string >( parameter );
-                       // URLエンコード済みのクエリ形式文字列に変換
-                       string paramString = MyCommon.BuildQueryString( sorted );
-                       // アクセス先URLの整形
-                       string url = string.Format( "{0}://{1}{2}", uri.Scheme, uri.Host, uri.AbsolutePath );
-                       // 署名のベース文字列生成(&区切り)。クエリ形式文字列は再エンコードする
-                       string signatureBase = string.Format( "{0}&{1}&{2}", method, MyCommon.UrlEncode( url ), MyCommon.UrlEncode( paramString ) );
-                       // 署名鍵の文字列をコンシューマー秘密鍵とアクセストークン秘密鍵から生成(&区切り。アクセストークン秘密鍵なくても&残すこと)
-                       string key = MyCommon.UrlEncode( this.consumerSecret ) + "&";
-                       if ( !string.IsNullOrEmpty( tokenSecret ) )
-                               key += MyCommon.UrlEncode( tokenSecret );
-                       // 鍵生成&署名生成
-                       using ( HMACSHA1 hmac = new HMACSHA1( Encoding.ASCII.GetBytes( key ) ) )
-                       {
-                               byte[] hash = hmac.ComputeHash( Encoding.ASCII.GetBytes( signatureBase ) );
-                               return Convert.ToBase64String( hash );
-                       }
+                       webRequest.Headers.Add( HttpRequestHeader.Authorization, credential );
                }
                #endregion // OAuth認証用ヘッダ作成・付加処理
 
index 3ae96bd..110570c 100644 (file)
@@ -25,6 +25,7 @@
 // Boston, MA 02110-1301, USA.
 
 using HttpConnectionOAuth = OpenTween.HttpConnectionOAuth;
+using OAuthUtility = OpenTween.Connection.OAuthUtility;
 using Uri = System.Uri;
 using HttpWebRequest = System.Net.HttpWebRequest;
 using System.Collections.Generic; // for Dictionary<TKey, TValue>, KeyValuePair<TKey, TValue>
@@ -51,21 +52,12 @@ namespace OpenTween
 
                protected override void AppendOAuthInfo( HttpWebRequest webRequest, Dictionary< string, string > query, string token, string tokenSecret )
                {
-                       // OAuth共通情報取得
-                       Dictionary< string, string > parameter = this.GetOAuthParameter( token );
-                       // OAuth共通情報にquery情報を追加
-                       if ( query != null )
-                               foreach ( KeyValuePair< string, string > item in query )
-                                       parameter.Add( item.Key, item.Value );
-                       // 署名の作成・追加(GETメソッド固定。ServiceProvider呼び出し用の署名作成)
-                       parameter.Add( "oauth_signature", this.CreateSignature( tokenSecret, HttpConnection.GetMethod, this._serviceProvider, parameter ) );
-                       // HTTPリクエストのヘッダに追加
-                       StringBuilder sb = new StringBuilder( "OAuth " );
-                       sb.AppendFormat( "realm=\"{0}://{1}{2}\",", this._realm.Scheme, this._realm.Host, this._realm.AbsolutePath);
-                       foreach ( KeyValuePair< string, string > item in parameter )
-                               if ( item.Key.StartsWith( "oauth_" ) )
-                                       sb.AppendFormat( "{0}=\"{1}\",", item.Key, MyCommon.UrlEncode( item.Value ) );
-                       webRequest.Headers.Add( "X-Verify-Credentials-Authorization", sb.ToString() );
+                       var realm = this._realm.Scheme + "://" + this._realm.Host + this._realm.AbsolutePath;
+
+                       var credential = OAuthUtility.CreateAuthorization( HttpConnection.GetMethod, this._serviceProvider, query,
+                               this.consumerKey, this.consumerSecret, token, tokenSecret, realm );
+
+                       webRequest.Headers.Add( "X-Verify-Credentials-Authorization", credential );
                        webRequest.Headers.Add( "X-Auth-Service-Provider", string.Format("{0}://{1}{2}", this._serviceProvider.Scheme, this._serviceProvider.Host, this._serviceProvider.AbsolutePath));
                }
 
index b227fa5..453b7ed 100644 (file)
 using System;
 using System.Collections.Generic;
 using System.Linq;
+using System.Net;
 using System.Text;
 using System.Security.Cryptography;
+using OpenTween.Connection;
 
 namespace OpenTween
 {
@@ -48,31 +50,22 @@ namespace OpenTween
             }
         }
 
-        protected override string CreateSignature(string tokenSecret,
-                                         string method,
-                                         Uri uri,
-                                         Dictionary<string, string> parameter)
+        protected override void AppendOAuthInfo(HttpWebRequest webRequest, Dictionary<string, string> query,
+            string token, string tokenSecret)
         {
-            //パラメタをソート済みディクショナリに詰替(OAuthの仕様)
-            SortedDictionary<string, string> sorted = new SortedDictionary<string, string>(parameter);
-            //URLエンコード済みのクエリ形式文字列に変換
-            string paramString = MyCommon.BuildQueryString(sorted);
-            //アクセス先URLの整形
-            string url = string.Format("{0}://{1}{2}", uri.Scheme, uri.Host, uri.AbsolutePath);
-            //本来のアクセス先URLに再設定(api.twitter.com固定)
-            if (!string.IsNullOrEmpty(_proxyHost) && url.StartsWith(uri.Scheme + "://" + _proxyHost))
-                url = url.Replace(uri.Scheme + "://" + _proxyHost, uri.Scheme + "://" + _apiHost);
-            //署名のベース文字列生成(&区切り)。クエリ形式文字列は再エンコードする
-            string signatureBase = String.Format("{0}&{1}&{2}", method, MyCommon.UrlEncode(url), MyCommon.UrlEncode(paramString));
-            //署名鍵の文字列をコンシューマー秘密鍵とアクセストークン秘密鍵から生成(&区切り。アクセストークン秘密鍵なくても&残すこと)
-            string key = MyCommon.UrlEncode(consumerSecret) + "&";
-            if (!string.IsNullOrEmpty(tokenSecret)) key += MyCommon.UrlEncode(tokenSecret);
-            //鍵生成&署名生成
-            using (HMACSHA1 hmac = new HMACSHA1(Encoding.ASCII.GetBytes(key)))
+            var requestUri = webRequest.RequestUri;
+
+            // 本来のアクセス先URLに再設定(api.twitter.com固定)
+            if (!string.IsNullOrEmpty(_proxyHost) && requestUri.Host == _proxyHost)
             {
-                byte[] hash = hmac.ComputeHash(Encoding.ASCII.GetBytes(signatureBase));
-                return Convert.ToBase64String(hash);
+                var rewriteUriStr = requestUri.GetLeftPart(UriPartial.Scheme) + _proxyHost + requestUri.PathAndQuery;
+                requestUri = new Uri(rewriteUriStr);
             }
+
+            var credential = OAuthUtility.CreateAuthorization(webRequest.Method, requestUri, query,
+                this.consumerKey, this.consumerSecret, token, tokenSecret);
+
+            webRequest.Headers.Add(HttpRequestHeader.Authorization, credential);
         }
 
     }
diff --git a/OpenTween/Connection/OAuthUtility.cs b/OpenTween/Connection/OAuthUtility.cs
new file mode 100644 (file)
index 0000000..f54b212
--- /dev/null
@@ -0,0 +1,135 @@
+// OpenTween - Client of Twitter
+// Copyright (c) 2007-2011 kiri_feather (@kiri_feather) <kiri.feather@gmail.com>
+//           (c) 2008-2011 Moz (@syo68k)
+//           (c) 2008-2011 takeshik (@takeshik) <http://www.takeshik.org/>
+//           (c) 2010-2011 anis774 (@anis774) <http://d.hatena.ne.jp/anis774/>
+//           (c) 2010-2011 fantasticswallow (@f_swallow) <http://twitter.com/f_swallow>
+//           (c) 2011      spinor (@tplantd) <http://d.hatena.ne.jp/spinor/>
+//           (c) 2015      kim_upsilon (@kim_upsilon) <https://upsilo.net/~upsilon/>
+// All rights reserved.
+//
+// This file is part of OpenTween.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program. If not, see <http://www.gnu.org/licenses/>, or write to
+// the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
+// Boston, MA 02110-1301, USA.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net;
+using System.Security.Cryptography;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace OpenTween.Connection
+{
+    public static class OAuthUtility
+    {
+        /// <summary>
+        /// OAuth署名のoauth_timestamp算出用基準日付(1970/1/1 00:00:00)
+        /// </summary>
+        private static readonly DateTime UnixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Unspecified);
+
+        /// <summary>
+        /// OAuth署名のoauth_nonce算出用乱数クラス
+        /// </summary>
+        private static readonly Random NonceRandom = new Random();
+
+        /// <summary>
+        /// HTTPリクエストに追加するAuthorizationヘッダの値を生成します
+        /// </summary>
+        /// <param name="httpMethod">リクエストのHTTPメソッド</param>
+        /// <param name="requestUri">リクエスト先のURI</param>
+        /// <param name="query">OAuth追加情報+クエリ or POSTデータ</param>
+        /// <param name="consumerKey">コンシューマーキー</param>
+        /// <param name="consumerSecret">コンシューマーシークレット</param>
+        /// <param name="token">アクセストークン、もしくはリクエストトークン。未取得なら空文字列</param>
+        /// <param name="tokenSecret">アクセストークンシークレット。認証処理では空文字列</param>
+        /// <param name="realm">realm (必要な場合のみ)</param>
+        public static string CreateAuthorization(string httpMethod, Uri requestUri, Dictionary<string, string> query,
+            string consumerKey, string consumerSecret, string token, string tokenSecret,
+            string realm = null)
+        {
+            // OAuth共通情報取得
+            Dictionary<string, string> parameter = GetOAuthParameter(consumerKey, token);
+            // OAuth共通情報にquery情報を追加
+            if (query != null)
+                foreach (KeyValuePair<string, string> item in query)
+                    parameter.Add(item.Key, item.Value);
+            // 署名の作成・追加
+            parameter.Add("oauth_signature", CreateSignature(consumerSecret, tokenSecret, httpMethod, requestUri, parameter));
+            // HTTPリクエストのヘッダに追加
+            StringBuilder sb = new StringBuilder("OAuth ");
+
+            if (realm != null)
+                sb.AppendFormat("realm=\"{0}\",", realm);
+
+            foreach (KeyValuePair<string, string> item in parameter)
+                // 各種情報のうち、oauth_で始まる情報のみ、ヘッダに追加する。各情報はカンマ区切り、データはダブルクォーテーションで括る
+                if (item.Key.StartsWith("oauth_"))
+                    sb.AppendFormat("{0}=\"{1}\",", item.Key, MyCommon.UrlEncode(item.Value));
+
+            return sb.ToString();
+        }
+
+        /// <summary>
+        /// OAuthで使用する共通情報を取得する
+        /// </summary>
+        /// <param name="token">アクセストークン、もしくはリクエストトークン。未取得なら空文字列</param>
+        /// <returns>OAuth情報のディクショナリ</returns>
+        public static Dictionary<string, string> GetOAuthParameter(string consumerKey, string token)
+        {
+            Dictionary<string, string> parameter = new Dictionary<string, string>();
+            parameter.Add("oauth_consumer_key", consumerKey);
+            parameter.Add("oauth_signature_method", "HMAC-SHA1");
+            parameter.Add("oauth_timestamp", Convert.ToInt64((DateTime.UtcNow - UnixEpoch).TotalSeconds).ToString()); // epoch秒
+            parameter.Add("oauth_nonce", NonceRandom.Next(123400, 9999999).ToString());
+            parameter.Add("oauth_version", "1.0");
+            if (!string.IsNullOrEmpty(token))
+                parameter.Add("oauth_token", token); // トークンがあれば追加
+            return parameter;
+        }
+
+        /// <summary>
+        /// OAuth認証ヘッダの署名作成
+        /// </summary>
+        /// <param name="tokenSecret">アクセストークン秘密鍵</param>
+        /// <param name="method">HTTPメソッド文字列</param>
+        /// <param name="uri">アクセス先Uri</param>
+        /// <param name="parameter">クエリ、もしくはPOSTデータ</param>
+        /// <returns>署名文字列</returns>
+        public static string CreateSignature(string consumerSecret, string tokenSecret, string method, Uri uri, Dictionary<string, string> parameter)
+        {
+            // パラメタをソート済みディクショナリに詰替(OAuthの仕様)
+            SortedDictionary<string, string> sorted = new SortedDictionary<string, string>(parameter);
+            // URLエンコード済みのクエリ形式文字列に変換
+            string paramString = MyCommon.BuildQueryString(sorted);
+            // アクセス先URLの整形
+            string url = string.Format("{0}://{1}{2}", uri.Scheme, uri.Host, uri.AbsolutePath);
+            // 署名のベース文字列生成(&区切り)。クエリ形式文字列は再エンコードする
+            string signatureBase = string.Format("{0}&{1}&{2}", method, MyCommon.UrlEncode(url), MyCommon.UrlEncode(paramString));
+            // 署名鍵の文字列をコンシューマー秘密鍵とアクセストークン秘密鍵から生成(&区切り。アクセストークン秘密鍵なくても&残すこと)
+            string key = MyCommon.UrlEncode(consumerSecret) + "&";
+            if (!string.IsNullOrEmpty(tokenSecret))
+                key += MyCommon.UrlEncode(tokenSecret);
+            // 鍵生成&署名生成
+            using (HMACSHA1 hmac = new HMACSHA1(Encoding.ASCII.GetBytes(key)))
+            {
+                byte[] hash = hmac.ComputeHash(Encoding.ASCII.GetBytes(signatureBase));
+                return Convert.ToBase64String(hash);
+            }
+        }
+    }
+}
index 643bbcc..5e538d5 100644 (file)
     <Compile Include="Connection\Imgur.cs" />
     <Compile Include="Connection\Mobypicture.cs" />
     <Compile Include="Connection\Networking.cs" />
+    <Compile Include="Connection\OAuthUtility.cs" />
     <Compile Include="Connection\TwipplePhoto.cs" />
     <Compile Include="EmojiFormatter.cs" />
     <Compile Include="EventViewerDialog.cs">