+++ /dev/null
-' Tween - 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>
-' All rights reserved.
-'
-' This file is part of Tween.
-'
-' 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.
-
-Imports System.Collections.Specialized
-Imports System.Diagnostics
-Imports System.IO
-Imports System.Net
-Imports System.Security
-Imports System.Text
-
-'''<summary>
-'''OAuth認証を使用するHTTP通信。HMAC-SHA1固定
-'''</summary>
-'''<remarks>
-'''使用前に認証情報を設定する。認証確認を伴う場合はAuthenticate系のメソッドを、認証不要な場合はInitializeを呼ぶこと。
-'''</remarks>
-Public Class HttpConnectionOAuth
- Inherits HttpConnection
- Implements IHttpConnection
-
- '''<summary>
- '''OAuth署名のoauth_timestamp算出用基準日付(1970/1/1 00:00:00)
- '''</summary>
- Private Shared ReadOnly UnixEpoch As New DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Unspecified)
-
- '''<summary>
- '''OAuth署名のoauth_nonce算出用乱数クラス
- '''</summary>
- Private Shared ReadOnly NonceRandom As New Random
-
- '''<summary>
- '''OAuthのアクセストークン。永続化可能(ユーザー取り消しの可能性はある)。
- '''</summary>
- Private token As String = ""
-
- '''<summary>
- '''OAuthの署名作成用秘密アクセストークン。永続化可能(ユーザー取り消しの可能性はある)。
- '''</summary>
- Private tokenSecret As String = ""
-
- '''<summary>
- '''OAuthのコンシューマー鍵
- '''</summary>
- Private consumerKey As String
-
- '''<summary>
- '''OAuthの署名作成用秘密コンシューマーデータ
- '''</summary>
- Protected consumerSecret As String
-
- '''<summary>
- '''認証成功時の応答でユーザー情報を取得する場合のキー。設定しない場合は、AuthUsernameもブランクのままとなる
- '''</summary>
- Private userIdentKey As String = ""
-
- '''<summary>
- '''認証成功時の応答でユーザーID情報を取得する場合のキー。設定しない場合は、AuthUserIdもブランクのままとなる
- '''</summary>
- Private userIdIdentKey As String = ""
-
- '''<summary>
- '''認証完了時の応答からuserIdentKey情報に基づいて取得するユーザー情報
- '''</summary>
- Private authorizedUsername As String = ""
-
- '''<summary>
- '''認証完了時の応答からuserIdentKey情報に基づいて取得するユーザー情報
- '''</summary>
- Private authorizedUserId As Long
-
- '''<summary>
- '''Stream用のHttpWebRequest
- '''</summary>
- Private streamReq As HttpWebRequest = Nothing
-
- '''<summary>
- '''OAuth認証で指定のURLとHTTP通信を行い、結果を返す
- '''</summary>
- '''<param name="method">HTTP通信メソッド(GET/HEAD/POST/PUT/DELETE)</param>
- '''<param name="requestUri">通信先URI</param>
- '''<param name="param">GET時のクエリ、またはPOST時のエンティティボディ</param>
- '''<param name="content">[OUT]HTTP応答のボディデータ</param>
- '''<param name="headerInfo">[IN/OUT]HTTP応答のヘッダ情報。必要なヘッダ名を事前に設定しておくこと</param>
- '''<param name="callback">処理終了直前に呼ばれるコールバック関数のデリゲート 不要な場合はNothingを渡すこと</param>
- '''<returns>HTTP応答のステータスコード</returns>
- Public Function GetContent(ByVal method As String, _
- ByVal requestUri As Uri, _
- ByVal param As Dictionary(Of String, String), _
- ByRef content As String, _
- ByVal headerInfo As Dictionary(Of String, String), _
- ByVal callback As CallbackDelegate) As HttpStatusCode Implements IHttpConnection.GetContent
- '認証済かチェック
- If String.IsNullOrEmpty(token) Then Return HttpStatusCode.Unauthorized
-
- Dim webReq As HttpWebRequest = CreateRequest(method, _
- requestUri, _
- param, _
- False)
- 'OAuth認証ヘッダを付加
- AppendOAuthInfo(webReq, param, token, tokenSecret)
-
- Dim code As HttpStatusCode
- If content Is Nothing Then
- code = GetResponse(webReq, headerInfo, False)
- Else
- code = GetResponse(webReq, content, headerInfo, False)
- End If
- If callback IsNot Nothing Then
- Dim frame As New StackFrame(1)
- callback(frame.GetMethod.Name, code, content)
- End If
- Return code
- End Function
-
- '''<summary>
- '''バイナリアップロード
- '''</summary>
- Public Function GetContent(ByVal method As String, _
- ByVal requestUri As Uri, _
- ByVal param As Dictionary(Of String, String), _
- ByVal binary As List(Of KeyValuePair(Of String, FileInfo)), _
- ByRef content As String, _
- ByVal headerInfo As Dictionary(Of String, String), _
- ByVal callback As CallbackDelegate) As HttpStatusCode Implements IHttpConnection.GetContent
- '認証済かチェック
- If String.IsNullOrEmpty(token) Then Return HttpStatusCode.Unauthorized
-
- Dim webReq As HttpWebRequest = CreateRequest(method, _
- requestUri, _
- param, _
- binary, _
- False)
- 'OAuth認証ヘッダを付加
- AppendOAuthInfo(webReq, Nothing, token, tokenSecret)
-
- Dim code As HttpStatusCode
- If content Is Nothing Then
- code = GetResponse(webReq, headerInfo, False)
- Else
- code = GetResponse(webReq, content, headerInfo, False)
- End If
- If callback IsNot Nothing Then
- Dim frame As New StackFrame(1)
- callback(frame.GetMethod.Name, code, content)
- End If
- Return code
- End Function
-
- '''<summary>
- '''OAuth認証で指定のURLとHTTP通信を行い、ストリームを返す
- '''</summary>
- '''<param name="method">HTTP通信メソッド(GET/HEAD/POST/PUT/DELETE)</param>
- '''<param name="requestUri">通信先URI</param>
- '''<param name="param">GET時のクエリ、またはPOST時のエンティティボディ</param>
- '''<param name="content">[OUT]HTTP応答のボディストリーム</param>
- '''<returns>HTTP応答のステータスコード</returns>
- Public Function GetContent(ByVal method As String, _
- ByVal requestUri As Uri, _
- ByVal param As Dictionary(Of String, String), _
- ByRef content As Stream,
- ByVal userAgent As String) As HttpStatusCode Implements IHttpConnection.GetContent
- '認証済かチェック
- If String.IsNullOrEmpty(token) Then Return HttpStatusCode.Unauthorized
-
- Me.RequestAbort()
- streamReq = CreateRequest(method, requestUri, param, False)
- 'User-Agent指定がある場合は付加
- If Not String.IsNullOrEmpty(userAgent) Then streamReq.UserAgent = userAgent
-
- 'OAuth認証ヘッダを付加
- AppendOAuthInfo(streamReq, param, token, tokenSecret)
-
- Try
- Dim webRes As HttpWebResponse = CType(streamReq.GetResponse(), HttpWebResponse)
- content = webRes.GetResponseStream()
- Return webRes.StatusCode
- Catch ex As WebException
- If ex.Status = WebExceptionStatus.ProtocolError Then
- Dim res As HttpWebResponse = DirectCast(ex.Response, HttpWebResponse)
- Return res.StatusCode
- End If
- Throw
- End Try
-
- End Function
-
- Public Sub RequestAbort() Implements IHttpConnection.RequestAbort
- Try
- If streamReq IsNot Nothing Then
- streamReq.Abort()
- streamReq = Nothing
- End If
- Catch ex As Exception
- End Try
- End Sub
-
-
-#Region "認証処理"
- '''<summary>
- '''OAuth認証の開始要求(リクエストトークン取得)。PIN入力用の前段
- '''</summary>
- '''<remarks>
- '''呼び出し元では戻されたurlをブラウザで開き、認証完了後PIN入力を受け付けて、リクエストトークンと共にAuthenticatePinFlowを呼び出す
- '''</remarks>
- '''<param name="requestTokenUrl">リクエストトークンの取得先URL</param>
- '''<param name="requestUri">ブラウザで開く認証用URLのベース</param>
- '''<param name="requestToken">[OUT]認証要求で戻されるリクエストトークン。使い捨て</param>
- '''<param name="authUri">[OUT]requestUriを元に生成された認証用URL。通常はリクエストトークンをクエリとして付加したUri</param>
- '''<returns>取得結果真偽値</returns>
- Public Function AuthenticatePinFlowRequest(ByVal requestTokenUrl As String, _
- ByVal authorizeUrl As String, _
- ByRef requestToken As String, _
- ByRef authUri As Uri) As Boolean
- 'PIN-based flow
- authUri = GetAuthenticatePageUri(requestTokenUrl, authorizeUrl, requestToken)
- If authUri Is Nothing Then Return False
- Return True
- End Function
-
- '''<summary>
- '''OAuth認証のアクセストークン取得。PIN入力用の後段
- '''</summary>
- '''<remarks>
- '''事前にAuthenticatePinFlowRequestを呼んで、ブラウザで認証後に表示されるPINを入力してもらい、その値とともに呼び出すこと
- '''</remarks>
- '''<param name="accessTokenUrl">アクセストークンの取得先URL</param>
- '''<param name="requestUri">AuthenticatePinFlowRequestで取得したリクエストトークン</param>
- '''<param name="pinCode">Webで認証後に表示されるPINコード</param>
- '''<returns>取得結果真偽値</returns>
- Public Function AuthenticatePinFlow(ByVal accessTokenUrl As String, _
- ByVal requestToken As String, _
- ByVal pinCode As String) As HttpStatusCode
- 'PIN-based flow
- If String.IsNullOrEmpty(requestToken) Then Throw New Exception("Sequence error.(requestToken is blank)")
-
- 'アクセストークン取得
- Dim content As String = ""
- Dim accessTokenData As NameValueCollection
- Dim httpCode As HttpStatusCode = GetOAuthToken(New Uri(accessTokenUrl), pinCode, requestToken, Nothing, content)
- If httpCode <> HttpStatusCode.OK Then Return httpCode
- accessTokenData = ParseQueryString(content)
-
- If accessTokenData IsNot Nothing Then
- token = accessTokenData.Item("oauth_token")
- tokenSecret = accessTokenData.Item("oauth_token_secret")
- 'サービスごとの独自拡張対応
- If Me.userIdentKey <> "" Then
- authorizedUsername = accessTokenData.Item(Me.userIdentKey)
- Else
- authorizedUsername = ""
- End If
- If Me.userIdIdentKey <> "" Then
- Try
- authorizedUserId = CLng(accessTokenData.Item(Me.userIdIdentKey))
- Catch ex As Exception
- authorizedUserId = 0
- End Try
- Else
- authorizedUserId = 0
- End If
- If token = "" Then Throw New InvalidDataException("Token is null.")
- Return HttpStatusCode.OK
- Else
- Throw New InvalidDataException("Return value is null.")
- End If
- End Function
-
- '''<summary>
- '''OAuth認証のアクセストークン取得。xAuth方式
- '''</summary>
- '''<param name="accessTokenUrl">アクセストークンの取得先URL</param>
- '''<param name="username">認証用ユーザー名</param>
- '''<param name="password">認証用パスワード</param>
- '''<returns>取得結果真偽値</returns>
- Public Function AuthenticateXAuth(ByVal accessTokenUrl As Uri, ByVal username As String, ByVal password As String, ByRef content As String) As HttpStatusCode Implements IHttpConnection.Authenticate
- 'ユーザー・パスワードチェック
- If String.IsNullOrEmpty(username) OrElse String.IsNullOrEmpty(password) Then
- Throw New Exception("Sequence error.(username or password is blank)")
- End If
- 'xAuthの拡張パラメータ設定
- Dim parameter As New Dictionary(Of String, String)
- parameter.Add("x_auth_mode", "client_auth")
- parameter.Add("x_auth_username", username)
- parameter.Add("x_auth_password", password)
-
- 'アクセストークン取得
- Dim httpCode As HttpStatusCode = GetOAuthToken(accessTokenUrl, "", "", parameter, content)
- If httpCode <> HttpStatusCode.OK Then Return httpCode
- Dim accessTokenData As NameValueCollection = ParseQueryString(content)
-
- If accessTokenData IsNot Nothing Then
- token = accessTokenData.Item("oauth_token")
- tokenSecret = accessTokenData.Item("oauth_token_secret")
- 'サービスごとの独自拡張対応
- If Me.userIdentKey <> "" Then
- authorizedUsername = accessTokenData.Item(Me.userIdentKey)
- Else
- authorizedUsername = ""
- End If
- If Me.userIdIdentKey <> "" Then
- Try
- authorizedUserId = CLng(accessTokenData.Item(Me.userIdIdentKey))
- Catch ex As Exception
- authorizedUserId = 0
- End Try
- Else
- authorizedUserId = 0
- End If
- If token = "" Then Throw New InvalidDataException("Token is null.")
- Return HttpStatusCode.OK
- Else
- Throw New InvalidDataException("Return value is null.")
- End If
- End Function
-
- '''<summary>
- '''OAuth認証のリクエストトークン取得。リクエストトークンと組み合わせた認証用のUriも生成する
- '''</summary>
- '''<param name="accessTokenUrl">リクエストトークンの取得先URL</param>
- '''<param name="authorizeUrl">ブラウザで開く認証用URLのベース</param>
- '''<param name="requestToken">[OUT]取得したリクエストトークン</param>
- '''<returns>取得結果真偽値</returns>
- Private Function GetAuthenticatePageUri(ByVal requestTokenUrl As String, _
- ByVal authorizeUrl As String, _
- ByRef requestToken As String) As Uri
- Const tokenKey As String = "oauth_token"
-
- 'リクエストトークン取得
- Dim content As String = ""
- Dim reqTokenData As NameValueCollection
- If GetOAuthToken(New Uri(requestTokenUrl), "", "", Nothing, content) <> HttpStatusCode.OK Then Return Nothing
- reqTokenData = ParseQueryString(content)
-
- If reqTokenData IsNot Nothing Then
- requestToken = reqTokenData.Item(tokenKey)
- 'Uri生成
- Dim ub As New UriBuilder(authorizeUrl)
- ub.Query = String.Format("{0}={1}", tokenKey, requestToken)
- Return ub.Uri
- Else
- Return Nothing
- End If
- End Function
-
- '''<summary>
- '''OAuth認証のトークン取得共通処理
- '''</summary>
- '''<param name="requestUri">各種トークンの取得先URL</param>
- '''<param name="pinCode">PINフロー時のアクセストークン取得時に設定。それ以外は空文字列</param>
- '''<param name="requestToken">PINフロー時のリクエストトークン取得時に設定。それ以外は空文字列</param>
- '''<param name="parameter">追加パラメータ。xAuthで使用</param>
- '''<returns>取得結果のデータ。正しく取得出来なかった場合はNothing</returns>
- Private Function GetOAuthToken(ByVal requestUri As Uri, ByVal pinCode As String, ByVal requestToken As String, ByVal parameter As Dictionary(Of String, String), ByRef content As String) As HttpStatusCode
- Dim webReq As HttpWebRequest = Nothing
- 'HTTPリクエスト生成。PINコードもパラメータも未指定の場合はGETメソッドで通信。それ以外はPOST
- If String.IsNullOrEmpty(pinCode) AndAlso parameter Is Nothing Then
- webReq = CreateRequest("GET", requestUri, Nothing, False)
- Else
- webReq = CreateRequest("POST", requestUri, parameter, False) 'ボディに追加パラメータ書き込み
- End If
- 'OAuth関連パラメータ準備。追加パラメータがあれば追加
- Dim query As New Dictionary(Of String, String)
- If parameter IsNot Nothing Then
- For Each kvp As KeyValuePair(Of String, String) In parameter
- query.Add(kvp.Key, kvp.Value)
- Next
- End If
- 'PINコードが指定されていればパラメータに追加
- If Not String.IsNullOrEmpty(pinCode) Then query.Add("oauth_verifier", pinCode)
- 'OAuth関連情報をHTTPリクエストに追加
- AppendOAuthInfo(webReq, query, requestToken, "")
- 'HTTP応答取得
- Dim header As New Dictionary(Of String, String) From {{"Date", ""}}
- Dim responseCode As HttpStatusCode = GetResponse(webReq, content, header, False)
- If responseCode = HttpStatusCode.OK Then Return responseCode
- If Not String.IsNullOrEmpty(header("Date")) Then content += Environment.NewLine + "Check the Date & Time of this computer." + Environment.NewLine + "Server:" + CDate(header("Date")).ToString + " PC:" + Now.ToString
- Return responseCode
- End Function
-#End Region
-
-#Region "OAuth認証用ヘッダ作成・付加処理"
- '''<summary>
- '''HTTPリクエストにOAuth関連ヘッダを追加
- '''</summary>
- '''<param name="webRequest">追加対象のHTTPリクエスト</param>
- '''<param name="query">OAuth追加情報+クエリ or POSTデータ</param>
- '''<param name="token">アクセストークン、もしくはリクエストトークン。未取得なら空文字列</param>
- '''<param name="tokenSecret">アクセストークンシークレット。認証処理では空文字列</param>
- Protected Overridable Sub AppendOAuthInfo(ByVal webRequest As HttpWebRequest, _
- ByVal query As Dictionary(Of String, String), _
- ByVal token As String, _
- ByVal tokenSecret As String)
- 'OAuth共通情報取得
- Dim parameter As Dictionary(Of String, String) = GetOAuthParameter(token)
- 'OAuth共通情報にquery情報を追加
- If query IsNot Nothing Then
- For Each item As KeyValuePair(Of String, String) In query
- parameter.Add(item.Key, item.Value)
- Next
- End If
- '署名の作成・追加
- parameter.Add("oauth_signature", CreateSignature(tokenSecret, webRequest.Method, webRequest.RequestUri, parameter))
- 'HTTPリクエストのヘッダに追加
- Dim sb As New StringBuilder("OAuth ")
- For Each item As KeyValuePair(Of String, String) In parameter
- '各種情報のうち、oauth_で始まる情報のみ、ヘッダに追加する。各情報はカンマ区切り、データはダブルクォーテーションで括る
- If item.Key.StartsWith("oauth_") Then
- sb.AppendFormat("{0}=""{1}"",", item.Key, UrlEncode(item.Value))
- End If
- Next
- webRequest.Headers.Add(HttpRequestHeader.Authorization, sb.ToString)
- End Sub
-
- '''<summary>
- '''OAuthで使用する共通情報を取得する
- '''</summary>
- '''<param name="token">アクセストークン、もしくはリクエストトークン。未取得なら空文字列</param>
- '''<returns>OAuth情報のディクショナリ</returns>
- Protected Function GetOAuthParameter(ByVal token As String) As Dictionary(Of String, String)
- Dim parameter As New Dictionary(Of 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 Not String.IsNullOrEmpty(token) Then parameter.Add("oauth_token", token) 'トークンがあれば追加
- Return parameter
- End Function
-
- '''<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 Overridable Function CreateSignature(ByVal tokenSecret As String, _
- ByVal method As String, _
- ByVal uri As Uri, _
- ByVal parameter As Dictionary(Of String, String) _
- ) As String
- 'パラメタをソート済みディクショナリに詰替(OAuthの仕様)
- Dim sorted As New SortedDictionary(Of String, String)(parameter)
- 'URLエンコード済みのクエリ形式文字列に変換
- Dim paramString As String = CreateQueryString(sorted)
- 'アクセス先URLの整形
- Dim url As String = String.Format("{0}://{1}{2}", uri.Scheme, uri.Host, uri.AbsolutePath)
- '署名のベース文字列生成(&区切り)。クエリ形式文字列は再エンコードする
- Dim signatureBase As String = String.Format("{0}&{1}&{2}", method, UrlEncode(url), UrlEncode(paramString))
- '署名鍵の文字列をコンシューマー秘密鍵とアクセストークン秘密鍵から生成(&区切り。アクセストークン秘密鍵なくても&残すこと)
- Dim key As String = UrlEncode(consumerSecret) + "&"
- If Not String.IsNullOrEmpty(tokenSecret) Then key += UrlEncode(tokenSecret)
- '鍵生成&署名生成
- Using hmac As New Cryptography.HMACSHA1(Encoding.ASCII.GetBytes(key))
- Dim hash As Byte() = hmac.ComputeHash(Encoding.ASCII.GetBytes(signatureBase))
- Return Convert.ToBase64String(hash)
- End Using
- End Function
-
-#End Region
-
- '''<summary>
- '''初期化。各種トークンの設定とユーザー識別情報設定
- '''</summary>
- '''<param name="consumerKey">コンシューマー鍵</param>
- '''<param name="consumerSecret">コンシューマー秘密鍵</param>
- '''<param name="accessToken">アクセストークン</param>
- '''<param name="accessTokenSecret">アクセストークン秘密鍵</param>
- '''<param name="userIdentifier">アクセストークン取得時に得られるユーザー識別情報。不要なら空文字列</param>
- Public Sub Initialize(ByVal consumerKey As String, _
- ByVal consumerSecret As String, _
- ByVal accessToken As String, _
- ByVal accessTokenSecret As String, _
- ByVal userIdentifier As String,
- ByVal userIdIdentifier As String)
- Me.consumerKey = consumerKey
- Me.consumerSecret = consumerSecret
- Me.token = accessToken
- Me.tokenSecret = accessTokenSecret
- Me.userIdentKey = userIdentifier
- Me.userIdIdentKey = userIdIdentifier
- End Sub
-
- '''<summary>
- '''初期化。各種トークンの設定とユーザー識別情報設定
- '''</summary>
- '''<param name="consumerKey">コンシューマー鍵</param>
- '''<param name="consumerSecret">コンシューマー秘密鍵</param>
- '''<param name="accessToken">アクセストークン</param>
- '''<param name="accessTokenSecret">アクセストークン秘密鍵</param>
- '''<param name="username">認証済みユーザー名</param>
- '''<param name="userIdentifier">アクセストークン取得時に得られるユーザー識別情報。不要なら空文字列</param>
- Public Sub Initialize(ByVal consumerKey As String, _
- ByVal consumerSecret As String, _
- ByVal accessToken As String, _
- ByVal accessTokenSecret As String, _
- ByVal username As String, _
- ByVal userId As Long,
- ByVal userIdentifier As String,
- ByVal userIdIdentifier As String)
- Initialize(consumerKey, consumerSecret, accessToken, accessTokenSecret, userIdentifier, userIdIdentifier)
- authorizedUsername = username
- authorizedUserId = userId
- End Sub
-
- '''<summary>
- '''アクセストークン
- '''</summary>
- Public ReadOnly Property AccessToken() As String
- Get
- Return token
- End Get
- End Property
-
- '''<summary>
- '''アクセストークン秘密鍵
- '''</summary>
- Public ReadOnly Property AccessTokenSecret() As String
- Get
- Return tokenSecret
- End Get
- End Property
-
- '''<summary>
- '''認証済みユーザー名
- '''</summary>
- Public ReadOnly Property AuthUsername() As String Implements IHttpConnection.AuthUsername
- Get
- Return authorizedUsername
- End Get
- End Property
-
- '''<summary>
- '''認証済みユーザーId
- '''</summary>
- Public Property AuthUserId() As Long Implements IHttpConnection.AuthUserId
- Get
- Return authorizedUserId
- End Get
- Set(ByVal value As Long)
- authorizedUserId = value
- End Set
- End Property
-
-End Class
+++ /dev/null
-' Tween - 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>
-' All rights reserved.
-'
-' This file is part of Tween.
-'
-' 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.
-
-Imports System.Net
-Imports System.Text
-
-Public Class HttpConnectionOAuthEcho
- Inherits HttpConnectionOAuth
-
- Private _realm As Uri
- Private _serviceProvider As Uri
- Private _token As String
- Private _tokenSecret As String
-
- Public WriteOnly Property Realm As Uri
- Set(ByVal value As Uri)
- _realm = value
- End Set
- End Property
-
- Public WriteOnly Property ServiceProvider As Uri
- Set(ByVal value As Uri)
- _serviceProvider = value
- End Set
- End Property
-
- Protected Overrides Sub AppendOAuthInfo(ByVal webRequest As HttpWebRequest, _
- ByVal query As Dictionary(Of String, String), _
- ByVal token As String, _
- ByVal tokenSecret As String)
- 'OAuth共通情報取得
- Dim parameter As Dictionary(Of String, String) = GetOAuthParameter(token)
- 'OAuth共通情報にquery情報を追加
- If query IsNot Nothing Then
- For Each item As KeyValuePair(Of String, String) In query
- parameter.Add(item.Key, item.Value)
- Next
- End If
- '署名の作成・追加(GETメソッド固定。ServiceProvider呼び出し用の署名作成)
- parameter.Add("oauth_signature", CreateSignature(tokenSecret, GetMethod, _serviceProvider, parameter))
- 'HTTPリクエストのヘッダに追加
- Dim sb As New StringBuilder("OAuth ")
- sb.AppendFormat("realm=""{0}://{1}{2}"",", _realm.Scheme, _realm.Host, _realm.AbsolutePath)
- For Each item As KeyValuePair(Of String, String) In parameter
- '各種情報のうち、oauth_で始まる情報のみ、ヘッダに追加する。各情報はカンマ区切り、データはダブルクォーテーションで括る
- If item.Key.StartsWith("oauth_") Then
- sb.AppendFormat("{0}=""{1}"",", item.Key, UrlEncode(item.Value))
- End If
- Next
- webRequest.Headers.Add("X-Verify-Credentials-Authorization", sb.ToString)
- webRequest.Headers.Add("X-Auth-Service-Provider", String.Format("{0}://{1}{2}", _serviceProvider.Scheme, _serviceProvider.Host, _serviceProvider.AbsolutePath))
- End Sub
-
-
- Public Sub New(ByVal realm As Uri, ByVal serviceProvider As Uri)
- _realm = realm
- _serviceProvider = serviceProvider
- End Sub
-End Class
<Compile Include="AuthBrowser.vb">
<SubType>Form</SubType>
</Compile>
- <Compile Include="Connection\HttpConnectionOAuthEcho.vb" />
<Compile Include="Connection\HttpOAuthApiProxy.vb" />
- <Compile Include="Connection\HttpConnectionOAuth.vb" />
<Compile Include="Connection\HttpTwitter.vb" />
<Compile Include="Connection\Plixi.vb" />
<Compile Include="Connection\TwitPic.vb" />
--- /dev/null
+// 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/>
+// 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 HttpConnection = Tween.HttpConnection;
+using IHttpConnection = Tween.IHttpConnection;
+using DateTime = System.DateTime;
+using DateTimeKind = System.DateTimeKind;
+using Random = System.Random;
+using HttpWebRequest = System.Net.HttpWebRequest;
+using HttpStatusCode = System.Net.HttpStatusCode;
+using Uri = System.Uri;
+using System.Collections.Generic; // for Dictionary<TKey, TValue>, List<T>, KeyValuePair<TKey, TValue>, SortedDictionary<TKey, TValue>
+using CallbackDelegate = Tween.CallbackDelegate;
+using StackFrame = System.Diagnostics.StackFrame;
+using FileInfo = System.IO.FileInfo;
+using Stream = System.IO.Stream;
+using HttpWebResponse = System.Net.HttpWebResponse;
+using WebException = System.Net.WebException;
+using WebExceptionStatus = System.Net.WebExceptionStatus;
+using Exception = System.Exception;
+using NameValueCollection = System.Collections.Specialized.NameValueCollection;
+using Convert = System.Convert;
+using InvalidDataException = System.IO.InvalidDataException;
+using UriBuilder = System.UriBuilder;
+using Environment = System.Environment;
+using DateTime = System.DateTime;
+using StringBuilder = System.Text.StringBuilder;
+using HttpRequestHeader = System.Net.HttpRequestHeader;
+using HMACSHA1 = System.Security.Cryptography.HMACSHA1;
+using Encoding = System.Text.Encoding;
+
+namespace Tween
+{
+ /// <summary>
+ /// OAuth認証を使用するHTTP通信。HMAC-SHA1固定
+ /// </summary>
+ /// <remarks>
+ /// 使用前に認証情報を設定する。認証確認を伴う場合はAuthenticate系のメソッドを、認証不要な場合はInitializeを呼ぶこと。
+ /// </remarks>
+ public class HttpConnectionOAuth : HttpConnection, IHttpConnection
+ {
+ /// <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>
+ /// OAuthのアクセストークン。永続化可能(ユーザー取り消しの可能性はある)。
+ /// </summary>
+ private string token = "";
+
+ /// <summary>
+ /// OAuthの署名作成用秘密アクセストークン。永続化可能(ユーザー取り消しの可能性はある)。
+ /// </summary>
+ private string tokenSecret = "";
+
+ /// <summary>
+ /// OAuthのコンシューマー鍵
+ /// </summary>
+ private string consumerKey;
+
+ /// <summary>
+ /// OAuthの署名作成用秘密コンシューマーデータ
+ /// </summary>
+ private string consumerSecret;
+
+ /// <summary>
+ /// 認証成功時の応答でユーザー情報を取得する場合のキー。設定しない場合は、AuthUsernameもブランクのままとなる
+ /// </summary>
+ private string userIdentKey = "";
+
+ /// <summary>
+ /// 認証成功時の応答でユーザーID情報を取得する場合のキー。設定しない場合は、AuthUserIdもブランクのままとなる
+ /// </summary>
+ private string userIdIdentKey = "";
+
+ /// <summary>
+ /// 認証完了時の応答からuserIdentKey情報に基づいて取得するユーザー情報
+ /// </summary>
+ private string authorizedUsername = "";
+
+ /// <summary>
+ /// 認証完了時の応答からuserIdentKey情報に基づいて取得するユーザー情報
+ /// </summary>
+ private long authorizedUserId;
+
+ /// <summary>
+ /// Stream用のHttpWebRequest
+ /// </summary>
+ private HttpWebRequest streamReq = null;
+
+ /// <summary>
+ /// OAuth認証で指定のURLとHTTP通信を行い、結果を返す
+ /// </summary>
+ /// <param name="method">HTTP通信メソッド(GET/HEAD/POST/PUT/DELETE)</param>
+ /// <param name="requestUri">通信先URI</param>
+ /// <param name="param">GET時のクエリ、またはPOST時のエンティティボディ</param>
+ /// <param name="content">[OUT]HTTP応答のボディデータ</param>
+ /// <param name="headerInfo">[IN/OUT]HTTP応答のヘッダ情報。必要なヘッダ名を事前に設定しておくこと</param>
+ /// <param name="callback">処理終了直前に呼ばれるコールバック関数のデリゲート 不要な場合はNothingを渡すこと</param>
+ /// <returns>HTTP応答のステータスコード</returns>
+ public HttpStatusCode GetContent( string method,
+ Uri requestUri,
+ Dictionary< string, string > param,
+ ref string content,
+ Dictionary< string, string > headerInfo,
+ CallbackDelegate callback )
+ {
+ // 認証済かチェック
+ if ( string.IsNullOrEmpty( token ) )
+ return HttpStatusCode.Unauthorized;
+
+ HttpWebRequest webReq = this.CreateRequest( method, requestUri, param, false );
+ // OAuth認証ヘッダを付加
+ this.AppendOAuthInfo( webReq, param, token, tokenSecret );
+
+ HttpStatusCode code;
+ if ( content == null )
+ code = this.GetResponse( webReq, headerInfo, false );
+ else
+ code = this.GetResponse( webReq, ref content, headerInfo, false );
+
+ if ( callback != null )
+ {
+ StackFrame frame = new StackFrame( 1 );
+ callback( frame.GetMethod().Name, ref code, ref content );
+ }
+ return code;
+ }
+
+ /// <summary>
+ /// バイナリアップロード
+ /// </summary>
+ public HttpStatusCode GetContent( string method,
+ Uri requestUri,
+ Dictionary< string, string > param,
+ List< KeyValuePair< string, FileInfo > > binary,
+ ref string content,
+ Dictionary< string, string > headerInfo,
+ CallbackDelegate callback )
+ {
+ // 認証済かチェック
+ if ( string.IsNullOrEmpty( token ) )
+ return HttpStatusCode.Unauthorized;
+
+ HttpWebRequest webReq = this.CreateRequest( method, requestUri, param, binary, false );
+ // OAuth認証ヘッダを付加
+ this.AppendOAuthInfo( webReq, null, token, tokenSecret );
+
+ HttpStatusCode code;
+ if ( content == null )
+ code = this.GetResponse( webReq, headerInfo, false );
+ else
+ code = this.GetResponse( webReq, ref content, headerInfo, false );
+
+ if ( callback != null )
+ {
+ StackFrame frame = new StackFrame( 1 );
+ callback( frame.GetMethod().Name, ref code, ref content );
+ }
+ return code;
+ }
+
+ /// <summary>
+ /// OAuth認証で指定のURLとHTTP通信を行い、ストリームを返す
+ /// </summary>
+ /// <param name="method">HTTP通信メソッド(GET/HEAD/POST/PUT/DELETE)</param>
+ /// <param name="requestUri">通信先URI</param>
+ /// <param name="param">GET時のクエリ、またはPOST時のエンティティボディ</param>
+ /// <param name="content">[OUT]HTTP応答のボディストリーム</param>
+ /// <returns>HTTP応答のステータスコード</returns>
+ public HttpStatusCode GetContent( string method,
+ Uri requestUri,
+ Dictionary< string, string > param,
+ ref Stream content,
+ string userAgent )
+ {
+ // 認証済かチェック
+ if ( string.IsNullOrEmpty( token ) )
+ return HttpStatusCode.Unauthorized;
+
+ this.RequestAbort();
+ this.streamReq = this.CreateRequest( method, requestUri, param, false );
+ // User-Agent指定がある場合は付加
+ if ( !string.IsNullOrEmpty( userAgent ) )
+ this.streamReq.UserAgent = userAgent;
+
+ // OAuth認証ヘッダを付加
+ this.AppendOAuthInfo( this.streamReq, param, token, tokenSecret );
+
+ try
+ {
+ HttpWebResponse webRes = (HttpWebResponse)this.streamReq.GetResponse();
+ content = webRes.GetResponseStream();
+ return webRes.StatusCode;
+ }
+ catch ( WebException ex )
+ {
+ if ( ex.Status == WebExceptionStatus.ProtocolError )
+ {
+ HttpWebResponse res = (HttpWebResponse)ex.Response;
+ return res.StatusCode;
+ }
+ throw;
+ }
+ }
+
+ public void RequestAbort()
+ {
+ try
+ {
+ if ( this.streamReq != null )
+ {
+ this.streamReq.Abort();
+ this.streamReq = null;
+ }
+ }
+ catch ( Exception ) {}
+ }
+
+ #region "認証処理"
+ /// <summary>
+ /// OAuth認証の開始要求(リクエストトークン取得)。PIN入力用の前段
+ /// </summary>
+ /// <remarks>
+ /// 呼び出し元では戻されたurlをブラウザで開き、認証完了後PIN入力を受け付けて、リクエストトークンと共にAuthenticatePinFlowを呼び出す
+ /// </remarks>
+ /// <param name="requestTokenUrl">リクエストトークンの取得先URL</param>
+ /// <param name="requestUri">ブラウザで開く認証用URLのベース</param>
+ /// <param name="requestToken">[OUT]認証要求で戻されるリクエストトークン。使い捨て</param>
+ /// <param name="authUri">[OUT]requestUriを元に生成された認証用URL。通常はリクエストトークンをクエリとして付加したUri</param>
+ /// <returns>取得結果真偽値</returns>
+ public bool AuthenticatePinFlowRequest( string requestTokenUrl, string authorizeUrl, ref string requestToken, ref Uri authUri )
+ {
+ // PIN-based flow
+ authUri = this.GetAuthenticatePageUri( requestTokenUrl, authorizeUrl, ref requestToken );
+ if ( authUri == null )
+ return false;
+ return true;
+ }
+
+ /// <summary>
+ /// OAuth認証のアクセストークン取得。PIN入力用の後段
+ /// </summary>
+ /// <remarks>
+ /// 事前にAuthenticatePinFlowRequestを呼んで、ブラウザで認証後に表示されるPINを入力してもらい、その値とともに呼び出すこと
+ /// </remarks>
+ /// <param name="accessTokenUrl">アクセストークンの取得先URL</param>
+ /// <param name="requestUri">AuthenticatePinFlowRequestで取得したリクエストトークン</param>
+ /// <param name="pinCode">Webで認証後に表示されるPINコード</param>
+ /// <returns>取得結果真偽値</returns>
+ HttpStatusCode AuthenticatePinFlow( string accessTokenUrl, string requestToken, string pinCode )
+ {
+ // PIN-based flow
+ if ( string.IsNullOrEmpty( requestToken ) )
+ throw new Exception( "Sequence error.(requestToken is blank)" );
+
+ // アクセストークン取得
+ string content = "";
+ NameValueCollection accessTokenData;
+ HttpStatusCode httpCode = this.GetOAuthToken( new Uri( accessTokenUrl ), pinCode, requestToken, null, ref content );
+ if ( httpCode != HttpStatusCode.OK )
+ return httpCode;
+ accessTokenData = base.ParseQueryString( content );
+
+ if ( accessTokenData != null )
+ {
+ this.token = accessTokenData[ "oauth_token" ];
+ this.tokenSecret = accessTokenData[ "oauth_token_secret" ];
+
+ // サービスごとの独自拡張対応
+ if ( this.userIdentKey != "" )
+ this.authorizedUsername = accessTokenData[ this.userIdentKey ];
+ else
+ this.authorizedUsername = "";
+
+ if ( this.userIdIdentKey != "" )
+ {
+ try
+ {
+ this.authorizedUserId = Convert.ToInt64( accessTokenData[ this.userIdIdentKey ] );
+ }
+ catch ( Exception )
+ {
+ this.authorizedUserId = 0;
+ }
+ }
+ else
+ {
+ this.authorizedUserId = 0;
+ }
+
+ if ( token == "" )
+ throw new InvalidDataException( "Token is null." );
+ return HttpStatusCode.OK;
+ }
+ else
+ {
+ throw new InvalidDataException( "Return value is null." );
+ }
+ }
+
+ /// <summary>
+ /// OAuth認証のアクセストークン取得。xAuth方式
+ /// </summary>
+ /// <param name="accessTokenUrl">アクセストークンの取得先URL</param>
+ /// <param name="username">認証用ユーザー名</param>
+ /// <param name="password">認証用パスワード</param>
+ /// <returns>取得結果真偽値</returns>
+ public HttpStatusCode AuthenticateXAuth( Uri accessTokenUrl, string username, string password, ref string content )
+ {
+ // ユーザー・パスワードチェック
+ if ( string.IsNullOrEmpty( username ) || string.IsNullOrEmpty( password ) )
+ throw new Exception( "Sequence error.(username or password is blank)" );
+
+ // xAuthの拡張パラメータ設定
+ Dictionary< string, string > parameter = new Dictionary< string, string >();
+ parameter.Add( "x_auth_mode", "client_auth" );
+ parameter.Add( "x_auth_username", username );
+ parameter.Add( "x_auth_password", password );
+
+ // アクセストークン取得
+ HttpStatusCode httpCode = this.GetOAuthToken( accessTokenUrl, "", "", parameter, ref content );
+ if ( httpCode != HttpStatusCode.OK )
+ return httpCode;
+ NameValueCollection accessTokenData = base.ParseQueryString( content );
+
+ if ( accessTokenData != null )
+ {
+ this.token = accessTokenData[ "oauth_token" ];
+ this.tokenSecret = accessTokenData[ "oauth_token_secret" ];
+
+ // サービスごとの独自拡張対応
+ if ( this.userIdentKey != "" )
+ this.authorizedUsername = accessTokenData[ this.userIdentKey ];
+ else
+ this.authorizedUsername = "";
+
+ if ( this.userIdIdentKey != "" )
+ {
+ try
+ {
+ this.authorizedUserId = Convert.ToInt64( accessTokenData[ this.userIdIdentKey ] );
+ }
+ catch ( Exception )
+ {
+ this.authorizedUserId = 0;
+ }
+ }
+ else
+ {
+ this.authorizedUserId = 0;
+ }
+
+ if ( token == "" )
+ throw new InvalidDataException( "Token is null." );
+ return HttpStatusCode.OK;
+ }
+ else
+ {
+ throw new InvalidDataException( "Return value is null." );
+ }
+ }
+
+ /// <summary>
+ /// OAuth認証のリクエストトークン取得。リクエストトークンと組み合わせた認証用のUriも生成する
+ /// </summary>
+ /// <param name="accessTokenUrl">リクエストトークンの取得先URL</param>
+ /// <param name="authorizeUrl">ブラウザで開く認証用URLのベース</param>
+ /// <param name="requestToken">[OUT]取得したリクエストトークン</param>
+ /// <returns>取得結果真偽値</returns>
+ private Uri GetAuthenticatePageUri( string requestTokenUrl, string authorizeUrl, ref string requestToken )
+ {
+ const string tokenKey = "oauth_token";
+
+ // リクエストトークン取得
+ string content = "";
+ NameValueCollection reqTokenData;
+ if ( this.GetOAuthToken( new Uri( requestTokenUrl ), "", "", null, ref content) != HttpStatusCode.OK )
+ return null;
+ reqTokenData = base.ParseQueryString( content );
+
+ if ( reqTokenData != null )
+ {
+ requestToken = reqTokenData[ tokenKey ];
+ // Uri生成
+ UriBuilder ub = new UriBuilder( authorizeUrl );
+ ub.Query = string.Format( "{0}={1}", tokenKey, requestToken );
+ return ub.Uri;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /// <summary>
+ /// OAuth認証のトークン取得共通処理
+ /// </summary>
+ /// <param name="requestUri">各種トークンの取得先URL</param>
+ /// <param name="pinCode">PINフロー時のアクセストークン取得時に設定。それ以外は空文字列</param>
+ /// <param name="requestToken">PINフロー時のリクエストトークン取得時に設定。それ以外は空文字列</param>
+ /// <param name="parameter">追加パラメータ。xAuthで使用</param>
+ /// <returns>取得結果のデータ。正しく取得出来なかった場合はNothing</returns>
+ private HttpStatusCode GetOAuthToken( Uri requestUri, string pinCode, string requestToken, Dictionary< string , string > parameter, ref string content )
+ {
+ HttpWebRequest webReq = null;
+ // HTTPリクエスト生成。PINコードもパラメータも未指定の場合はGETメソッドで通信。それ以外はPOST
+ if ( string.IsNullOrEmpty( pinCode ) && parameter != null )
+ webReq = this.CreateRequest( "GET", requestUri, null, false );
+ else
+ webReq = this.CreateRequest( "POST", requestUri, parameter, false ); // ボディに追加パラメータ書き込み
+
+ // OAuth関連パラメータ準備。追加パラメータがあれば追加
+ Dictionary< string, string > query = new Dictionary< string, string >();
+ if ( parameter != null )
+ foreach ( KeyValuePair< string, string > kvp in parameter )
+ query.Add( kvp.Key, kvp.Value );
+
+ // PINコードが指定されていればパラメータに追加
+ if ( string.IsNullOrEmpty( pinCode ) )
+ query.Add( "oauth_verifier", pinCode );
+ // OAuth関連情報をHTTPリクエストに追加
+ this.AppendOAuthInfo( webReq, query, requestToken, "" );
+
+ // HTTP応答取得
+ Dictionary< string, string > header = new Dictionary< string, string >() { { "Date", "" } };
+ HttpStatusCode responseCode = this.GetResponse( webReq, ref content, header, false );
+ if ( responseCode == HttpStatusCode.OK )
+ return responseCode;
+
+ if ( !string.IsNullOrEmpty( header[ "Date" ] ) )
+ content += Environment.NewLine + "Check the Date & Time of this computer." + Environment.NewLine
+ + "Server:" + DateTime.Parse( header[ "Date" ] ).ToString() + " PC:" + DateTime.Now.ToString();
+ return responseCode;
+ }
+ #endregion // 認証処理
+
+ #region "OAuth認証用ヘッダ作成・付加処理"
+ /// <summary>
+ /// HTTPリクエストにOAuth関連ヘッダを追加
+ /// </summary>
+ /// <param name="webRequest">追加対象のHTTPリクエスト</param>
+ /// <param name="query">OAuth追加情報+クエリ or POSTデータ</param>
+ /// <param name="token">アクセストークン、もしくはリクエストトークン。未取得なら空文字列</param>
+ /// <param name="tokenSecret">アクセストークンシークレット。認証処理では空文字列</param>
+ 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 );
+ // 署名の作成・追加
+ 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, this.UrlEncode( item.Value ) );
+ webRequest.Headers.Add( HttpRequestHeader.Authorization, sb.ToString() );
+ }
+
+ /// <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 override 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 = this.CreateQueryString( sorted );
+ // アクセス先URLの整形
+ string url = string.Format( "{0}://{1}{2}", uri.Scheme, uri.Host, uri.AbsolutePath );
+ // 署名のベース文字列生成(&区切り)。クエリ形式文字列は再エンコードする
+ string signatureBase = string.Format( "{0}&{1}&{2}", method, this.UrlEncode( url ), this.UrlEncode( paramString ) );
+ // 署名鍵の文字列をコンシューマー秘密鍵とアクセストークン秘密鍵から生成(&区切り。アクセストークン秘密鍵なくても&残すこと)
+ string key = this.UrlEncode( this.consumerSecret ) + "&";
+ if ( !string.IsNullOrEmpty( tokenSecret ) )
+ key += this.UrlEncode( tokenSecret );
+ // 鍵生成&署名生成
+ using ( HMACSHA1 hmac = new HMACSHA1( Encoding.ASCII.GetBytes( key ) ) )
+ {
+ byte[] hash = hmac.ComputeHash( Encoding.ASCII.GetBytes( signatureBase ) );
+ return Convert.ToBase64String( hash );
+ }
+ }
+ #endregion // OAuth認証用ヘッダ作成・付加処理
+
+ /// <summary>
+ /// 初期化。各種トークンの設定とユーザー識別情報設定
+ /// </summary>
+ /// <param name="consumerKey">コンシューマー鍵</param>
+ /// <param name="consumerSecret">コンシューマー秘密鍵</param>
+ /// <param name="accessToken">アクセストークン</param>
+ /// <param name="accessTokenSecret">アクセストークン秘密鍵</param>
+ /// <param name="userIdentifier">アクセストークン取得時に得られるユーザー識別情報。不要なら空文字列</param>
+ public void Initialize( string consumerKey, string consumerSecret,
+ string accessToken, string accessTokenSecret,
+ string userIdentifier, string userIdIdentifier )
+ {
+ this.consumerKey = consumerKey;
+ this.consumerSecret = consumerSecret;
+ this.token = accessToken;
+ this.tokenSecret = accessTokenSecret;
+ this.userIdentKey = userIdentifier;
+ this.userIdIdentKey = userIdIdentifier;
+ }
+
+ /// <summary>
+ /// 初期化。各種トークンの設定とユーザー識別情報設定
+ /// </summary>
+ /// <param name="consumerKey">コンシューマー鍵</param>
+ /// <param name="consumerSecret">コンシューマー秘密鍵</param>
+ /// <param name="accessToken">アクセストークン</param>
+ /// <param name="accessTokenSecret">アクセストークン秘密鍵</param>
+ /// <param name="username">認証済みユーザー名</param>
+ /// <param name="userIdentifier">アクセストークン取得時に得られるユーザー識別情報。不要なら空文字列</param>
+ public void Initialize( string consumerKey, string consumerSecret,
+ string accessToken, string accessTokenSecret,
+ string username, long userId,
+ string userIdentifier, string userIdIdentifier )
+ {
+ this.Initialize( consumerKey, consumerSecret, accessToken, accessTokenSecret, userIdentifier, userIdIdentifier );
+ this.authorizedUsername = username;
+ this.authorizedUserId = userId;
+ }
+
+ /// <summary>
+ /// アクセストークン
+ /// </summary>
+ public string AccessToken
+ {
+ get { return this.token; }
+ }
+
+ /// <summary>
+ /// アクセストークン秘密鍵
+ /// </summary>
+ public string AccessTokenSecret
+ {
+ get { return this.tokenSecret; }
+ }
+
+ /// <summary>
+ /// 認証済みユーザー名
+ /// </summary>
+ public string AuthUsername
+ {
+ get { return this.authorizedUsername; }
+ }
+
+ /// <summary>
+ /// 認証済みユーザーId
+ /// </summary>
+ public long AuthUserId
+ {
+ get { return this.authorizedUserId; }
+ set { this.authorizedUserId = value; }
+ }
+ }
+}
--- /dev/null
+// 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/>
+// 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 HttpConnectionOAuth = Tween.HttpConnectionOAuth;
+using Uri = System.Uri;
+using HttpWebRequest = System.Net.HttpWebRequest;
+using System.Collections.Generic; // for Dictionary<TKey, TValue>, KeyValuePair<TKey, TValue>
+using HttpConnection = Tween.HttpConnection;
+using StringBuilder = System.Text.StringBuilder;
+
+namespace Tween
+{
+ public class HttpConnectionOAuthEcho : HttpConnectionOAuth
+ {
+ private Uri _realm;
+
+ private Uri _serviceProvider;
+
+ private string _token;
+
+ private string _tokenSecret;
+
+ public Uri Realm
+ {
+ set { this._realm = value; }
+ }
+
+ public Uri ServiceProvider
+ {
+ set { this._serviceProvider = value; }
+ }
+
+ 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, this.UrlEncode( item.Value ) );
+ webRequest.Headers.Add( "X-Verify-Credentials-Authorization", sb.ToString() );
+ webRequest.Headers.Add( "X-Auth-Service-Provider", string.Format("{0}://{1}{2}", this._serviceProvider.Scheme, this._serviceProvider.Host, this._serviceProvider.AbsolutePath));
+ }
+
+ public HttpConnectionOAuthEcho( Uri realm, Uri serviceProvider )
+ {
+ this._realm = realm;
+ this._serviceProvider = serviceProvider;
+ }
+ }
+}
<Compile Include="ApiInformation.cs" />
<Compile Include="Bing.cs" />
<Compile Include="Connection\HttpVarious.cs" />
+ <Compile Include="Connection\HttpConnectionOAuth.cs" />
+ <Compile Include="Connection\HttpConnectionOAuthEcho.cs" />
<Compile Include="Connection\IHttpConnection.cs" />
<Compile Include="Connection\IMultimediaShareService.cs" />
<Compile Include="DataModel.cs" />