Made the OAuth implementation work as specified, Imgur is working but the others need to be checked.

git-svn-id: http://svn.code.sf.net/p/greenshot/code/trunk@2050 7dccd23d-a4a3-4e1f-8c07-b4c1b4018ab4
This commit is contained in:
RKrom 2012-09-18 15:07:17 +00:00
parent 45e018d197
commit ade8e365b6
5 changed files with 371 additions and 525 deletions

View file

@ -100,39 +100,34 @@ namespace GreenshotImgurPlugin {
/// <param name="imageData">byte[] with image data</param> /// <param name="imageData">byte[] with image data</param>
/// <returns>ImgurResponse</returns> /// <returns>ImgurResponse</returns>
public static ImgurInfo UploadToImgur(byte[] imageData, int dataLength, string title, string filename) { public static ImgurInfo UploadToImgur(byte[] imageData, int dataLength, string title, string filename) {
StringBuilder uploadRequest = new StringBuilder(); IDictionary<string, string> uploadParameters = new Dictionary<string, string>();
// Add image // Add image
uploadRequest.Append("image="); uploadParameters.Add("image", System.Convert.ToBase64String(imageData, 0, dataLength));
uploadRequest.Append(OAuthHelper.UrlEncode3986(System.Convert.ToBase64String(imageData, 0, dataLength)));
// add type // add type
uploadRequest.Append("&type=base64"); uploadParameters.Add("type", "base64");
// add title // add title
if (title != null) { if (title != null) {
uploadRequest.Append("&title="); uploadParameters.Add("title", title);
uploadRequest.Append(OAuthHelper.UrlEncode3986(title));
} }
// add filename // add filename
if (filename != null) { if (filename != null) {
uploadRequest.Append("&name="); uploadParameters.Add("name", filename);
uploadRequest.Append(OAuthHelper.UrlEncode3986(filename));
} }
string url;
string responseString;
string responseString = null;
if (config.AnonymousAccess) { if (config.AnonymousAccess) {
// add key // add key
uploadRequest.Append("&key="); uploadParameters.Add("key", IMGUR_ANONYMOUS_API_KEY);
uploadRequest.Append(IMGUR_ANONYMOUS_API_KEY); HttpWebRequest webRequest = (HttpWebRequest)NetworkHelper.CreateWebRequest(config.ImgurApiUrl + "/upload");
url = config.ImgurApiUrl + "/upload";
HttpWebRequest webRequest = (HttpWebRequest)NetworkHelper.CreateWebRequest(url);
webRequest.Method = "POST"; webRequest.Method = "POST";
webRequest.ContentType = "application/x-www-form-urlencoded"; webRequest.ContentType = "application/x-www-form-urlencoded";
webRequest.ServicePoint.Expect100Continue = false; webRequest.ServicePoint.Expect100Continue = false;
using(StreamWriter streamWriter = new StreamWriter(webRequest.GetRequestStream())) { using(StreamWriter streamWriter = new StreamWriter(webRequest.GetRequestStream())) {
streamWriter.Write(uploadRequest.ToString()); string urloadText = NetworkHelper.GenerateQueryParameters(uploadParameters);
streamWriter.Write(urloadText);
} }
using (WebResponse response = webRequest.GetResponse()) { using (WebResponse response = webRequest.GetResponse()) {
LogCredits(response); LogCredits(response);
@ -142,37 +137,38 @@ namespace GreenshotImgurPlugin {
} }
} else { } else {
url = config.ImgurApiUrl + "/account/images"; OAuthSession oAuth = new OAuthSession();
OAuthHelper oAuth = new OAuthHelper();
oAuth.BrowserWidth = 650; oAuth.BrowserWidth = 650;
oAuth.BrowserHeight = 500; oAuth.BrowserHeight = 500;
oAuth.CallbackUrl = "http://getgreenshot.org"; oAuth.CallbackUrl = "http://getgreenshot.org";
oAuth.AccessTokenUrl = "http://api.imgur.com/oauth/access_token"; oAuth.AccessTokenUrl = "http://api.imgur.com/oauth/access_token";
oAuth.AuthorizeUrl = "http://api.imgur.com/oauth/authorize"; oAuth.AuthorizeUrl = "http://api.imgur.com/oauth/authorize";
oAuth.RequestTokenUrl = "http://api.imgur.com/oauth/request_token"; oAuth.RequestTokenUrl = "http://api.imgur.com/oauth/request_token";
oAuth.ConsumerKey = ImgurCredentials.CONSUMER_KEY; oAuth.ConsumerKey = "907d4455b8c38144d68c4f72190af4c40504a0ac7";
oAuth.ConsumerSecret = ImgurCredentials.CONSUMER_SECRET; oAuth.ConsumerSecret = "d33902ef409fea163ab755454c15b3d0";
oAuth.UserAgent = "Greenshot"; oAuth.UserAgent = "Greenshot";
if (string.IsNullOrEmpty(config.ImgurToken)) { oAuth.LoginTitle = "Imgur authorization";
LOG.Debug("Creating Imgur Token"); //oAuth.UseHTTPHeadersForAuthorization = false;
oAuth.getRequestToken(); oAuth.Token = config.ImgurToken;
if (string.IsNullOrEmpty(oAuth.authorizeToken("Imgur authorization"))) { oAuth.TokenSecret = config.ImgurTokenSecret;
LOG.Debug("User didn't authenticate!"); try {
return null; LOG.DebugFormat("Test: {0}", oAuth.oAuthWebRequest(HTTPMethod.GET, "http://api.imgur.com/2/account", null));
responseString = oAuth.oAuthWebRequest(HTTPMethod.POST, "http://api.imgur.com/2/account/images.xml", uploadParameters);
} catch (Exception ex) {
LOG.Error("Upload to imgur gave an exeption: ", ex);
throw ex;
} finally {
if (oAuth.Token != null) {
config.ImgurToken = oAuth.Token;
} }
string accessToken = oAuth.getAccessToken(); if (oAuth.TokenSecret != null) {
config.ImgurToken = oAuth.Token; config.ImgurTokenSecret = oAuth.TokenSecret;
config.ImgurTokenSecret = oAuth.TokenSecret; }
} else { IniConfig.Save();
LOG.Debug("Using stored Imgur Token");
oAuth.Token = config.ImgurToken;
oAuth.TokenSecret = config.ImgurTokenSecret;
} }
responseString = oAuth.oAuthWebRequest(OAuthHelper.Method.POST, url, uploadRequest.ToString());
} }
LOG.Info(responseString); LOG.Info(responseString);
ImgurInfo imgurInfo = ImgurInfo.ParseResponse(responseString); ImgurInfo imgurInfo = ImgurInfo.ParseResponse(responseString);
LOG.Debug("Upload to imgur was finished");
return imgurInfo; return imgurInfo;
} }

View file

@ -48,59 +48,39 @@ namespace GreenshotPhotobucketPlugin {
/// <param name="imageData">byte[] with image data</param> /// <param name="imageData">byte[] with image data</param>
/// <returns>PhotobucketResponse</returns> /// <returns>PhotobucketResponse</returns>
public static PhotobucketInfo UploadToPhotobucket(byte[] imageData, int dataLength, string title, string filename) { public static PhotobucketInfo UploadToPhotobucket(byte[] imageData, int dataLength, string title, string filename) {
StringBuilder uploadRequest = new StringBuilder();
uploadRequest.Append("identifier=greenshot");
// add type
uploadRequest.Append("&type=base64");
// Add image
uploadRequest.Append("&uploadfile=");
uploadRequest.Append(OAuthHelper.UrlEncode3986(System.Convert.ToBase64String(imageData, 0, dataLength)));
// add title
if (title != null) {
uploadRequest.Append("&title=");
uploadRequest.Append(OAuthHelper.UrlEncode3986(title));
}
// add filename
if (filename != null) {
uploadRequest.Append("&filename=");
uploadRequest.Append(OAuthHelper.UrlEncode3986(filename));
}
string url = "http://api.photobucket.com/album/greenshot/upload";
string responseString; string responseString;
OAuthHelper oAuth = new OAuthHelper(); OAuthSession oAuth = new OAuthSession();
// This url is configured in the Photobucket API settings in the Photobucket site!! // This url is configured in the Photobucket API settings in the Photobucket site!!
oAuth.CallbackUrl = "http://getgreenshot.org"; oAuth.CallbackUrl = "http://getgreenshot.org";
oAuth.AccessTokenUrl = "http://api.photobucket.com/login/access"; oAuth.AccessTokenUrl = "http://api.photobucket.com/login/access";
oAuth.AuthorizeUrl = "http://photobucket.com/apilogin/login"; oAuth.AuthorizeUrl = "http://photobucket.com/apilogin/login";
oAuth.RequestTokenUrl = "http://api.photobucket.com/login/request"; oAuth.RequestTokenUrl = "http://api.photobucket.com/login/request";
oAuth.ConsumerKey = ; oAuth.ConsumerKey = "149833145";
oAuth.ConsumerSecret = ; oAuth.ConsumerSecret = "ebd828180b11103c010c7e71c66f6bcb";
oAuth.UserAgent = "Greenshot"; oAuth.UserAgent = "Greenshot";
oAuth.BrowserWidth = 1010; oAuth.BrowserWidth = 1010;
oAuth.BrowserHeight = 400; oAuth.BrowserHeight = 400;
oAuth.CheckVerifier = false; oAuth.CheckVerifier = false;
if (string.IsNullOrEmpty(config.PhotobucketToken)) { oAuth.LoginTitle = "Photobucket authorization";
LOG.Debug("Creating Photobucket Token"); Dictionary<string ,string> parameters = new Dictionary<string, string>();
try { // add album
oAuth.getRequestToken(); parameters.Add("identifier", "greenshot");
} catch (Exception ex) { // add type
LOG.Error(ex); parameters.Add("type", "base64");
throw new NotSupportedException("Photobucket is not available: " + ex.Message); // Add image
} parameters.Add("uploadfile", System.Convert.ToBase64String(imageData, 0, dataLength));
LOG.Debug("Authorizing Photobucket"); // add title
if (string.IsNullOrEmpty(oAuth.authorizeToken("Photobucket authorization"))) { if (title != null) {
return null; parameters.Add("title", title);
}
string accessToken = oAuth.getAccessToken();
config.PhotobucketToken = oAuth.Token;
config.PhotobucketTokenSecret = oAuth.TokenSecret;
} else {
LOG.Debug("Using stored Photobucket Token");
oAuth.Token = config.PhotobucketToken;
oAuth.TokenSecret = config.PhotobucketTokenSecret;
} }
responseString = oAuth.oAuthWebRequest(OAuthHelper.Method.POST, url, uploadRequest.ToString()); // add filename
if (filename != null) {
parameters.Add("filename", filename);
}
responseString = oAuth.oAuthWebRequest(HTTPMethod.POST, "http://api.photobucket.com/album/greenshot/upload", parameters, null, null);
oAuth.Token = config.PhotobucketToken;
oAuth.TokenSecret = config.PhotobucketTokenSecret;
LOG.Info(responseString); LOG.Info(responseString);
PhotobucketInfo PhotobucketInfo = PhotobucketInfo.ParseResponse(responseString); PhotobucketInfo PhotobucketInfo = PhotobucketInfo.ParseResponse(responseString);
LOG.Debug("Upload to Photobucket was finished"); LOG.Debug("Upload to Photobucket was finished");

View file

@ -34,7 +34,7 @@ namespace GreenshotPlugin.Controls {
/// </summary> /// </summary>
public partial class OAuthLoginForm : Form { public partial class OAuthLoginForm : Form {
private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(OAuthLoginForm)); private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(OAuthLoginForm));
private OAuthHelper _oauth; private OAuthSession _oauthSession;
private String _token; private String _token;
private String _verifier; private String _verifier;
private String _tokenSecret; private String _tokenSecret;
@ -57,18 +57,18 @@ namespace GreenshotPlugin.Controls {
} }
} }
public OAuthLoginForm(OAuthHelper o, string browserTitle, int width, int height) { public OAuthLoginForm(OAuthSession o, string browserTitle, int width, int height) {
_oauth = o; _oauthSession = o;
_token = null; _token = null;
InitializeComponent(); InitializeComponent();
this.ClientSize = new System.Drawing.Size(width, height); this.ClientSize = new System.Drawing.Size(width, height);
this.Icon = GreenshotPlugin.Core.GreenshotResources.getGreenshotIcon(); this.Icon = GreenshotPlugin.Core.GreenshotResources.getGreenshotIcon();
this.Text = browserTitle; this.Text = browserTitle;
this.addressTextBox.Text = o.AuthorizationLink; this.addressTextBox.Text = o.AuthorizationLink;
_token = _oauth.Token; _token = _oauthSession.Token;
_tokenSecret = _oauth.TokenSecret; _tokenSecret = _oauthSession.TokenSecret;
browser.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(browser_DocumentCompleted); browser.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(browser_DocumentCompleted);
browser.Navigate(new Uri(_oauth.AuthorizationLink)); browser.Navigate(new Uri(_oauthSession.AuthorizationLink));
WindowDetails.ToForeground(this.Handle); WindowDetails.ToForeground(this.Handle);
} }
@ -88,15 +88,15 @@ namespace GreenshotPlugin.Controls {
} }
private void checkUrl() { private void checkUrl() {
if (browser.Url.ToString().StartsWith(_oauth.CallbackUrl)) { if (browser.Url.ToString().StartsWith(_oauthSession.CallbackUrl)) {
string queryParams = browser.Url.Query; string queryParams = browser.Url.Query;
if (queryParams.Length > 0) { if (queryParams.Length > 0) {
//Store the Token and Token Secret //Store the Token and Token Secret
NameValueCollection qs = NetworkHelper.ParseQueryString(queryParams); IDictionary<string, string> qs = NetworkHelper.ParseQueryString(queryParams);
if (qs["oauth_token"] != null) { if (qs.ContainsKey("oauth_token") && qs["oauth_token"] != null) {
_token = qs["oauth_token"]; _token = qs["oauth_token"];
} }
if (qs["oauth_verifier"] != null) { if (qs.ContainsKey("oauth_verifier") && qs["oauth_verifier"] != null) {
_verifier = qs["oauth_verifier"]; _verifier = qs["oauth_verifier"];
} }
} }

View file

@ -23,11 +23,13 @@ using System.Drawing;
using System.IO; using System.IO;
using System.Net; using System.Net;
using System.Text; using System.Text;
using System.Collections.Generic;
using System.Collections.Specialized; using System.Collections.Specialized;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using Greenshot.IniFile; using Greenshot.IniFile;
using System.Security.Cryptography.X509Certificates; using System.Security.Cryptography.X509Certificates;
using System.Net.Security; using System.Net.Security;
using System.Web;
namespace GreenshotPlugin.Core { namespace GreenshotPlugin.Core {
/// <summary> /// <summary>
@ -158,6 +160,26 @@ namespace GreenshotPlugin.Core {
return null; return null;
} }
/// <summary>
/// A wrapper around the EscapeDataString, as the limit is 32766 characters
/// See: http://msdn.microsoft.com/en-us/library/system.uri.escapedatastring%28v=vs.110%29.aspx
/// </summary>
/// <param name="text"></param>
/// <returns>escaped data string</returns>
public static string EscapeDataString(string text) {
if (!string.IsNullOrEmpty(text)) {
StringBuilder result = new StringBuilder();
int currentLocation = 0;
while (currentLocation < text.Length) {
string process = text.Substring(currentLocation, Math.Min(16384, text.Length - currentLocation));
result.Append(Uri.EscapeDataString(process));
currentLocation = currentLocation + 16384;
}
return result.ToString();
}
return null;
}
/// <summary> /// <summary>
/// UrlDecodes a string without requiring System.Web /// UrlDecodes a string without requiring System.Web
/// </summary> /// </summary>
@ -174,23 +196,50 @@ namespace GreenshotPlugin.Core {
/// ParseQueryString without the requirement for System.Web /// ParseQueryString without the requirement for System.Web
/// </summary> /// </summary>
/// <param name="s"></param> /// <param name="s"></param>
/// <returns></returns> /// <returns>Dictionary<string, string></returns>
public static NameValueCollection ParseQueryString(string s) { public static IDictionary<string, string> ParseQueryString(string s) {
NameValueCollection nvc = new NameValueCollection(); IDictionary<string, string> parameters = new SortedDictionary<string, string>();
// remove anything other than query string from url // remove anything other than query string from url
if (s.Contains("?")) { if (s.Contains("?")) {
s = s.Substring(s.IndexOf('?') + 1); s = s.Substring(s.IndexOf('?') + 1);
} }
foreach (string vp in Regex.Split(s, "&")) { foreach (string vp in Regex.Split(s, "&")) {
if (string.IsNullOrEmpty(vp)) {
continue;
}
string[] singlePair = Regex.Split(vp, "="); string[] singlePair = Regex.Split(vp, "=");
if (parameters.ContainsKey(singlePair[0])) {
parameters.Remove(singlePair[0]);
}
if (singlePair.Length == 2) { if (singlePair.Length == 2) {
nvc.Add(singlePair[0], singlePair[1]); parameters.Add(singlePair[0], singlePair[1]);
} else { } else {
// only one key with no value specified in query string // only one key with no value specified in query string
nvc.Add(singlePair[0], string.Empty); parameters.Add(singlePair[0], string.Empty);
} }
} }
return nvc; return parameters;
} }
/// <summary>
/// Generate the query paramters
/// </summary>
/// <param name="queryParameters">the list of query parameters</param>
/// <returns>a string with the query parameters</returns>
public static string GenerateQueryParameters(IDictionary<string, string> queryParameters) {
if (queryParameters == null || queryParameters.Count == 0) {
return string.Empty;
}
queryParameters = new SortedDictionary<string, string>(queryParameters);
StringBuilder sb = new StringBuilder();
foreach(string key in queryParameters.Keys) {
sb.AppendFormat(System.Globalization.CultureInfo.InvariantCulture, "{0}={1}&", key, UrlEncode(queryParameters[key]));
}
sb.Remove(sb.Length-1,1);
return sb.ToString();
}
} }
} }

View file

@ -29,88 +29,56 @@ using System.Text.RegularExpressions;
using GreenshotPlugin.Controls; using GreenshotPlugin.Controls;
namespace GreenshotPlugin.Core { namespace GreenshotPlugin.Core {
public class OAuthHelper { /// <summary>
private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(OAuthHelper)); /// Provides a predefined set of algorithms that are supported officially by the protocol
/// <summary> /// </summary>
/// Provides a predefined set of algorithms that are supported officially by the protocol public enum OAuthSignatureTypes {
/// </summary> HMACSHA1,
protected enum SignatureTypes { PLAINTEXT,
HMACSHA1, RSASHA1
PLAINTEXT, }
RSASHA1
} public enum HTTPMethod { GET, POST, PUT, DELETE };
/// <summary> public class OAuthSession {
/// Provides an internal structure to sort the query parameter private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(OAuthSession));
/// </summary> protected const string OAUTH_VERSION = "1.0";
protected class QueryParameter { protected const string OAUTH_PARAMETER_PREFIX = "oauth_";
private string name = null;
private string value = null;
public QueryParameter(string name, string value)
{
this.name = name;
this.value = value;
}
public string Name
{
get { return name; }
}
public string Value
{
get { return value; }
}
}
/// <summary>
/// Comparer class used to perform the sorting of the query parameters
/// </summary>
protected class QueryParameterComparer : IComparer<QueryParameter> {
#region IComparer<QueryParameter> Members
public int Compare(QueryParameter x, QueryParameter y) {
if (x.Name == y.Name) {
return string.Compare(x.Value, y.Value);
} else {
return string.Compare(x.Name, y.Name);
}
}
#endregion
}
protected const string OAuthVersion = "1.0";
protected const string OAuthParameterPrefix = "oauth_";
// //
// List of know and used oauth parameters' names // List of know and used oauth parameters' names
// //
protected const string OAuthConsumerKeyKey = "oauth_consumer_key"; protected const string OAUTH_CONSUMER_KEY_KEY = "oauth_consumer_key";
protected const string OAuthCallbackKey = "oauth_callback"; protected const string OAUTH_CALLBACK_KEY = "oauth_callback";
protected const string OAuthVersionKey = "oauth_version"; protected const string OAUTH_VERSION_KEY = "oauth_version";
protected const string OAuthSignatureMethodKey = "oauth_signature_method"; protected const string OAUTH_SIGNATURE_METHOD_KEY = "oauth_signature_method";
protected const string OAuthSignatureKey = "oauth_signature"; protected const string OAUTH_TIMESTAMP_KEY = "oauth_timestamp";
protected const string OAuthTimestampKey = "oauth_timestamp"; protected const string OAUTH_NONCE_KEY = "oauth_nonce";
protected const string OAuthNonceKey = "oauth_nonce"; protected const string OAUTH_TOKEN_KEY = "oauth_token";
protected const string OAuthTokenKey = "oauth_token"; protected const string OAUTH_VERIFIER_KEY = "oauth_verifier";
protected const string oAauthVerifierKey = "oauth_verifier"; protected const string OAUTH_TOKEN_SECRET_KEY = "oauth_token_secret";
protected const string OAuthTokenSecretKey = "oauth_token_secret"; protected const string OAUTH_SIGNATURE_KEY = "oauth_signature";
protected const string HMACSHA1SignatureType = "HMAC-SHA1"; protected const string HMACSHA1SignatureType = "HMAC-SHA1";
protected const string PlainTextSignatureType = "PLAINTEXT"; protected const string PlainTextSignatureType = "PLAINTEXT";
protected const string RSASHA1SignatureType = "RSA-SHA1"; protected const string RSASHA1SignatureType = "RSA-SHA1";
public enum Method { GET, POST, PUT, DELETE };
protected static Random random = new Random();
protected const string UNRESERVED_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~";
private string _userAgent = "Greenshot"; private string _userAgent = "Greenshot";
private string _callbackUrl = "http://getgreenshot.org"; private string _callbackUrl = "http://getgreenshot.org";
private bool checkVerifier = true; private bool checkVerifier = true;
private bool useHTTPHeadersForAuthorization = true;
private bool useAuthorization = true;
// default browser size // default browser size
private int _browserWidth = 864; private int _browserWidth = 864;
private int _browserHeight = 587; private int _browserHeight = 587;
private string loginTitle = "Authorize Greenshot access";
#region PublicPropertiies #region PublicPropertiies
public string ConsumerKey { get; set; } public string ConsumerKey { get; set; }
public string ConsumerSecret { get; set; } public string ConsumerSecret { get; set; }
@ -149,15 +117,36 @@ namespace GreenshotPlugin.Core {
set; set;
} }
public string TokenSecret { get; set; } public string TokenSecret { get; set; }
public string LoginTitle {
get {
return loginTitle;
}
set {
loginTitle = value;
}
}
public string Verifier {
get;
set;
}
public bool UseHTTPHeadersForAuthorization {
get {
return useHTTPHeadersForAuthorization;
}
set {
useHTTPHeadersForAuthorization = value;
}
}
public bool UseAuthorization {
get {
return useAuthorization;
}
set {
useAuthorization = value;
}
}
#endregion #endregion
protected Random random = new Random();
private string oauth_verifier;
public string Verifier { get { return oauth_verifier; } set { oauth_verifier = value; } }
protected const string unreservedChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~";
/// <summary> /// <summary>
/// Helper function to compute a hash value /// Helper function to compute a hash value
@ -165,7 +154,7 @@ namespace GreenshotPlugin.Core {
/// <param name="hashAlgorithm">The hashing algorithm used. If that algorithm needs some initialization, like HMAC and its derivatives, they should be initialized prior to passing it to this function</param> /// <param name="hashAlgorithm">The hashing algorithm used. If that algorithm needs some initialization, like HMAC and its derivatives, they should be initialized prior to passing it to this function</param>
/// <param name="data">The data to hash</param> /// <param name="data">The data to hash</param>
/// <returns>a Base64 string of the hash value</returns> /// <returns>a Base64 string of the hash value</returns>
private string ComputeHash(HashAlgorithm hashAlgorithm, string data) { private static string ComputeHash(HashAlgorithm hashAlgorithm, string data) {
if (hashAlgorithm == null) { if (hashAlgorithm == null) {
throw new ArgumentNullException("hashAlgorithm"); throw new ArgumentNullException("hashAlgorithm");
} }
@ -174,56 +163,31 @@ namespace GreenshotPlugin.Core {
throw new ArgumentNullException("data"); throw new ArgumentNullException("data");
} }
byte[] dataBuffer = System.Text.Encoding.ASCII.GetBytes(data); byte[] dataBuffer = System.Text.Encoding.UTF8.GetBytes(data);
byte[] hashBytes = hashAlgorithm.ComputeHash(dataBuffer); byte[] hashBytes = hashAlgorithm.ComputeHash(dataBuffer);
return Convert.ToBase64String(hashBytes); return Convert.ToBase64String(hashBytes);
} }
/// <summary> /// <summary>
/// Internal function to cut out all non oauth query string parameters (all parameters not begining with "oauth_") /// Generate the normalized paramter string
/// </summary> /// </summary>
/// <param name="parameters">The query string part of the Url</param> /// <param name="queryParameters">the list of query parameters</param>
/// <returns>A list of QueryParameter each containing the parameter name and value</returns> /// <returns>a string with the normalized query parameters</returns>
private List<QueryParameter> GetQueryParameters(string parameters) { private static string GenerateNormalizedParametersString(IDictionary<string, string> queryParameters) {
if (parameters.StartsWith("?")) { if (queryParameters == null || queryParameters.Count == 0) {
parameters = parameters.Remove(0, 1); return string.Empty;
} }
List<QueryParameter> result = new List<QueryParameter>(); queryParameters = new SortedDictionary<string, string>(queryParameters);
if (!string.IsNullOrEmpty(parameters)) { StringBuilder sb = new StringBuilder();
string[] p = parameters.Split('&'); foreach (string key in queryParameters.Keys) {
foreach (string s in p) { sb.AppendFormat(System.Globalization.CultureInfo.InvariantCulture, "{0}={1}&", key, UrlEncode3986(queryParameters[key]));
if (!string.IsNullOrEmpty(s) && !s.StartsWith(OAuthParameterPrefix)) {
if (s.IndexOf('=') > -1) {
string[] temp = s.Split('=');
result.Add(new QueryParameter(temp[0], temp[1]));
} else {
result.Add(new QueryParameter(s, string.Empty));
}
}
}
} }
sb.Remove(sb.Length - 1, 1);
return result; return sb.ToString();
}
/// <summary>
/// A wrapper around the EscapeDataString, as the limit is 32766 characters
/// See: http://msdn.microsoft.com/en-us/library/system.uri.escapedatastring%28v=vs.110%29.aspx
/// </summary>
/// <param name="dataString"></param>
/// <returns>escaped data string</returns>
private static StringBuilder EscapeDataStringToStringBuilder(string dataString) {
StringBuilder result = new StringBuilder();
int currentLocation = 0;
while (currentLocation < dataString.Length) {
string process = dataString.Substring(currentLocation, Math.Min(16384, dataString.Length - currentLocation));
result.Append(Uri.EscapeDataString(process));
currentLocation = currentLocation + 16384;
}
return result;
} }
/// <summary> /// <summary>
@ -232,170 +196,26 @@ namespace GreenshotPlugin.Core {
/// </summary> /// </summary>
/// <param name="value">The value to Url encode</param> /// <param name="value">The value to Url encode</param>
/// <returns>Returns a Url encoded string</returns> /// <returns>Returns a Url encoded string</returns>
public static string UrlEncode3986(string text) { /// <remarks>This will cause an ignorable CA1055 warning in code analysis.</remarks>
string[] UriRfc3986CharsToEscape = new[] { "!", "*", "'", "(", ")" }; private static string UrlEncode3986(string value) {
LOG.DebugFormat("Text size {0}", text.Length); StringBuilder result = new StringBuilder();
StringBuilder escaped = EscapeDataStringToStringBuilder(text);
for (int i = 0; i < UriRfc3986CharsToEscape.Length; i++) { foreach (char symbol in value) {
escaped.Replace(UriRfc3986CharsToEscape[i], Uri.HexEscape(UriRfc3986CharsToEscape[i][0])); if (UNRESERVED_CHARS.IndexOf(symbol) != -1) {
} result.Append(symbol);
return escaped.ToString(); } else {
} result.Append('%' + String.Format(System.Globalization.CultureInfo.InvariantCulture, "{0:X2}", (int)symbol));
/// <summary>
/// Normalizes the request parameters according to the spec
/// </summary>
/// <param name="parameters">The list of parameters already sorted</param>
/// <returns>a string representing the normalized parameters</returns>
protected string NormalizeRequestParameters(IList<QueryParameter> parameters) {
StringBuilder sb = new StringBuilder();
QueryParameter p = null;
for (int i = 0; i < parameters.Count; i++) {
p = parameters[i];
sb.AppendFormat("{0}={1}", p.Name, p.Value);
if (i < parameters.Count - 1) {
sb.Append("&");
} }
} }
return sb.ToString(); return result.ToString();
}
/// <summary>
/// Generate the signature base that is used to produce the signature
/// </summary>
/// <param name="url">The full url that needs to be signed including its non OAuth url parameters</param>
/// <param name="consumerKey">The consumer key</param>
/// <param name="token">The token, if available. If not available pass null or an empty string</param>
/// <param name="tokenSecret">The token secret, if available. If not available pass null or an empty string</param>
/// <param name="httpMethod">The http method used. Must be a valid HTTP method verb (POST,GET,PUT, etc)</param>
/// <param name="signatureType">The signature type. To use the default values use <see cref="OAuthBase.SignatureTypes">OAuthBase.SignatureTypes</see>.</param>
/// <returns>The signature base</returns>
protected string GenerateSignatureBase(Uri url, string consumerKey, string token, string tokenSecret, string httpMethod, string timeStamp, string nonce, string callback, string signatureType, out string normalizedUrl, out string normalizedRequestParameters) {
if (token == null) {
token = string.Empty;
}
if (tokenSecret == null) {
tokenSecret = string.Empty;
}
if (string.IsNullOrEmpty(consumerKey)) {
throw new ArgumentNullException("consumerKey");
}
if (string.IsNullOrEmpty(httpMethod)) {
throw new ArgumentNullException("httpMethod");
}
if (string.IsNullOrEmpty(signatureType)) {
throw new ArgumentNullException("signatureType");
}
normalizedUrl = null;
normalizedRequestParameters = null;
List<QueryParameter> parameters = GetQueryParameters(url.Query);
parameters.Add(new QueryParameter(OAuthVersionKey, OAuthVersion));
parameters.Add(new QueryParameter(OAuthNonceKey, nonce));
parameters.Add(new QueryParameter(OAuthTimestampKey, timeStamp));
parameters.Add(new QueryParameter(OAuthSignatureMethodKey, signatureType));
parameters.Add(new QueryParameter(OAuthConsumerKeyKey, consumerKey));
//TODO: Make this less of a hack
if (!string.IsNullOrEmpty(callback)) {
parameters.Add(new QueryParameter(OAuthCallbackKey, UrlEncode3986(callback)));
}
if (!string.IsNullOrEmpty(token)) {
parameters.Add(new QueryParameter(OAuthTokenKey, token));
}
if (!string.IsNullOrEmpty(oauth_verifier)) {
parameters.Add(new QueryParameter(oAauthVerifierKey, oauth_verifier));
}
parameters.Sort(new QueryParameterComparer());
normalizedUrl = string.Format("{0}://{1}", url.Scheme, url.Host);
if (!((url.Scheme == "http" && url.Port == 80) || (url.Scheme == "https" && url.Port == 443))) {
normalizedUrl += ":" + url.Port;
}
normalizedUrl += url.AbsolutePath;
normalizedRequestParameters = NormalizeRequestParameters(parameters);
StringBuilder signatureBase = new StringBuilder();
signatureBase.AppendFormat("{0}&", httpMethod.ToUpper());
signatureBase.AppendFormat("{0}&", UrlEncode3986(normalizedUrl));
signatureBase.AppendFormat("{0}", UrlEncode3986(normalizedRequestParameters));
return signatureBase.ToString();
}
/// <summary>
/// Generate the signature value based on the given signature base and hash algorithm
/// </summary>
/// <param name="signatureBase">The signature based as produced by the GenerateSignatureBase method or by any other means</param>
/// <param name="hash">The hash algorithm used to perform the hashing. If the hashing algorithm requires initialization or a key it should be set prior to calling this method</param>
/// <returns>A base64 string of the hash value</returns>
protected string GenerateSignatureUsingHash(string signatureBase, HashAlgorithm hash) {
return ComputeHash(hash, signatureBase);
}
/// <summary>
/// Generates a signature using the HMAC-SHA1 algorithm
/// </summary>
/// <param name="url">The full url that needs to be signed including its non OAuth url parameters</param>
/// <param name="consumerKey">The consumer key</param>
/// <param name="consumerSecret">The consumer seceret</param>
/// <param name="token">The token, if available. If not available pass null or an empty string</param>
/// <param name="tokenSecret">The token secret, if available. If not available pass null or an empty string</param>
/// <param name="httpMethod">The http method used. Must be a valid HTTP method verb (POST,GET,PUT, etc)</param>
/// <returns>A base64 string of the hash value</returns>
protected string GenerateSignature(Uri url, string consumerKey, string consumerSecret, string token, string tokenSecret, string httpMethod, string timeStamp, string nonce, string callback, out string normalizedUrl, out string normalizedRequestParameters) {
return GenerateSignature(url, consumerKey, consumerSecret, token, tokenSecret, httpMethod, timeStamp, nonce, callback, SignatureTypes.HMACSHA1, out normalizedUrl, out normalizedRequestParameters);
}
/// <summary>
/// Generates a signature using the specified signatureType
/// </summary>
/// <param name="url">The full url that needs to be signed including its non OAuth url parameters</param>
/// <param name="consumerKey">The consumer key</param>
/// <param name="consumerSecret">The consumer seceret</param>
/// <param name="token">The token, if available. If not available pass null or an empty string</param>
/// <param name="tokenSecret">The token secret, if available. If not available pass null or an empty string</param>
/// <param name="httpMethod">The http method used. Must be a valid HTTP method verb (POST,GET,PUT, etc)</param>
/// <param name="signatureType">The type of signature to use</param>
/// <returns>A base64 string of the hash value</returns>
protected string GenerateSignature(Uri url, string consumerKey, string consumerSecret, string token, string tokenSecret, string httpMethod, string timeStamp, string nonce, string callback, SignatureTypes signatureType, out string normalizedUrl, out string normalizedRequestParameters) {
normalizedUrl = null;
normalizedRequestParameters = null;
switch (signatureType) {
case SignatureTypes.PLAINTEXT:
return NetworkHelper.UrlEncode(string.Format("{0}&{1}", consumerSecret, tokenSecret));
case SignatureTypes.HMACSHA1:
string signatureBase = GenerateSignatureBase(url, consumerKey, token, tokenSecret, httpMethod, timeStamp, nonce, callback, HMACSHA1SignatureType, out normalizedUrl, out normalizedRequestParameters);
HMACSHA1 hmacsha1 = new HMACSHA1();
hmacsha1.Key = Encoding.ASCII.GetBytes(string.Format("{0}&{1}", UrlEncode3986(consumerSecret), string.IsNullOrEmpty(tokenSecret) ? "" : UrlEncode3986(tokenSecret)));
return GenerateSignatureUsingHash(signatureBase, hmacsha1);
case SignatureTypes.RSASHA1:
throw new NotImplementedException();
default:
throw new ArgumentException("Unknown signature type", "signatureType");
}
} }
/// <summary> /// <summary>
/// Generate the timestamp for the signature /// Generate the timestamp for the signature
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public static string GenerateTimeStamp() {
protected virtual string GenerateTimeStamp() {
// Default implementation of UNIX time of the current UTC time // Default implementation of UNIX time of the current UTC time
TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0); TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
return Convert.ToInt64(ts.TotalSeconds).ToString(); return Convert.ToInt64(ts.TotalSeconds).ToString();
@ -405,23 +225,22 @@ namespace GreenshotPlugin.Core {
/// Generate a nonce /// Generate a nonce
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
protected virtual string GenerateNonce() { public static string GenerateNonce() {
// Just a simple implementation of a random number between 123400 and 9999999 // Just a simple implementation of a random number between 123400 and 9999999
return random.Next(123400, 9999999).ToString(); return random.Next(123400, 9999999).ToString();
} }
/// <summary> /// <summary>
/// Get the request token using the consumer key and secret. Also initializes tokensecret /// Get the request token using the consumer key and secret. Also initializes tokensecret
/// </summary> /// </summary>
/// <returns>The request token.</returns> /// <returns>The request token.</returns>
public String getRequestToken() { private String getRequestToken() {
string ret = null; string ret = null;
string response = oAuthWebRequest(Method.POST, RequestTokenUrl, String.Empty); string response = oAuthWebRequestNoCheck(HTTPMethod.POST, RequestTokenUrl, null);
if (response.Length > 0) { if (response.Length > 0) {
NameValueCollection qs = NetworkHelper.ParseQueryString(response); IDictionary<string, string> qs = NetworkHelper.ParseQueryString(response);
if (qs[OAuthTokenKey] != null) { if (qs.ContainsKey(OAUTH_TOKEN_KEY)) {
this.Token = qs[OAuthTokenKey]; this.Token = qs[OAUTH_TOKEN_KEY];
this.TokenSecret = qs[OAuthTokenSecretKey]; this.TokenSecret = qs[OAUTH_TOKEN_SECRET_KEY];
ret = this.Token; ret = this.Token;
} }
} }
@ -432,13 +251,13 @@ namespace GreenshotPlugin.Core {
/// Authorize the token by showing the dialog /// Authorize the token by showing the dialog
/// </summary> /// </summary>
/// <returns>The request token.</returns> /// <returns>The request token.</returns>
public String authorizeToken(string browserTitle) { private String authorizeToken() {
if (string.IsNullOrEmpty(Token)) { if (string.IsNullOrEmpty(Token)) {
Exception e = new Exception("The request token is not set"); Exception e = new Exception("The request token is not set");
throw e; throw e;
} }
LOG.DebugFormat("Opening AuthorizationLink: {0}", AuthorizationLink); LOG.DebugFormat("Opening AuthorizationLink: {0}", AuthorizationLink);
OAuthLoginForm oAuthLoginForm = new OAuthLoginForm(this, browserTitle, BrowserWidth, BrowserHeight); OAuthLoginForm oAuthLoginForm = new OAuthLoginForm(this, LoginTitle, BrowserWidth, BrowserHeight);
oAuthLoginForm.ShowDialog(); oAuthLoginForm.ShowDialog();
Token = oAuthLoginForm.Token; Token = oAuthLoginForm.Token;
if (CheckVerifier) { if (CheckVerifier) {
@ -457,163 +276,200 @@ namespace GreenshotPlugin.Core {
/// Get the access token /// Get the access token
/// </summary> /// </summary>
/// <returns>The access token.</returns> /// <returns>The access token.</returns>
public String getAccessToken() { private String getAccessToken() {
if (string.IsNullOrEmpty(Token) || (CheckVerifier && string.IsNullOrEmpty(Verifier))) { if (string.IsNullOrEmpty(Token) || (CheckVerifier && string.IsNullOrEmpty(Verifier))) {
Exception e = new Exception("The request token and verifier were not set"); Exception e = new Exception("The request token and verifier were not set");
throw e; throw e;
} }
string response = oAuthWebRequest(Method.POST, AccessTokenUrl, string.Empty); string response = oAuthWebRequestNoCheck(HTTPMethod.POST, AccessTokenUrl, null);
if (response.Length > 0) { if (response.Length > 0) {
NameValueCollection qs = NetworkHelper.ParseQueryString(response); IDictionary<string, string> qs = NetworkHelper.ParseQueryString(response);
if (qs[OAuthTokenKey] != null) { if (qs.ContainsKey(OAUTH_TOKEN_KEY) && qs[OAUTH_TOKEN_KEY] != null) {
this.Token = qs[OAuthTokenKey]; this.Token = qs[OAUTH_TOKEN_KEY];
} }
if (qs[OAuthTokenSecretKey] != null) { if (qs.ContainsKey(OAUTH_TOKEN_SECRET_KEY) && qs[OAUTH_TOKEN_SECRET_KEY] != null) {
this.TokenSecret = qs[OAuthTokenSecretKey]; this.TokenSecret = qs[OAUTH_TOKEN_SECRET_KEY];
} }
} }
return Token; return Token;
} }
/// <summary>
/// This method goes through the whole authorize process, including a Authorization window.
/// </summary>
/// <returns>true if the process is completed</returns>
private bool authorize() {
LOG.Debug("Creating Token");
try {
getRequestToken();
} catch (Exception ex) {
LOG.Error(ex);
throw new NotSupportedException("Service is not available: " + ex.Message);
}
if (UseAuthorization && string.IsNullOrEmpty(authorizeToken())) {
LOG.Debug("User didn't authenticate!");
return false;
}
return getAccessToken() != null;
}
/// <summary> /// <summary>
/// Get the link to the authorization page for this application. /// Get the link to the authorization page for this application.
/// </summary> /// </summary>
/// <returns>The url with a valid request token, or a null string.</returns> /// <returns>The url with a valid request token, or a null string.</returns>
public string AuthorizationLink { public string AuthorizationLink {
get { get {
return AuthorizeUrl + "?" + OAuthTokenKey + "=" + this.Token + "&" + OAuthCallbackKey + "=" + UrlEncode3986(CallbackUrl); return AuthorizeUrl + "?" + OAUTH_TOKEN_KEY + "=" + this.Token + "&" + OAUTH_CALLBACK_KEY + "=" + UrlEncode3986(CallbackUrl);
} }
} }
/// <summary>
/// Wrapper
/// </summary>
/// <param name="method"></param>
/// <param name="requestURL"></param>
/// <param name="parameters"></param>
/// <returns></returns>
public string oAuthWebRequest(HTTPMethod method, string requestURL, IDictionary<string, string> parameters) {
return oAuthWebRequest(method, requestURL, parameters, null, null);
}
/// <summary> /// <summary>
/// Submit a web request using oAuth. /// Submit a web request using oAuth.
/// </summary> /// </summary>
/// <param name="method">GET or POST</param> /// <param name="method">GET or POST</param>
/// <param name="url">The full url, including the querystring.</param> /// <param name="requestURL">The full url, including the querystring.</param>
/// <param name="parameters">Parameters for the request</param>
/// <param name="contentType">contenttype for the postdata</param>
/// <param name="postData">Data to post (MemoryStream)</param> /// <param name="postData">Data to post (MemoryStream)</param>
/// <returns>The web server response.</returns> /// <returns>The web server response.</returns>
public string oAuthWebRequest(Method method, string url, MemoryStream postData) { public string oAuthWebRequest(HTTPMethod method, string requestURL, IDictionary<string, string> parameters, string contentType, MemoryStream postData) {
string outUrl = ""; // If we are not trying to get a Authorization or Accestoken, and we don't have a token, create one
string querystring = ""; if (string.IsNullOrEmpty(Token)) {
if (!authorize()) {
Uri uri = new Uri(url); throw new Exception("Not authorized");
}
string nonce = this.GenerateNonce();
string timeStamp = this.GenerateTimeStamp();
string callback = "";
if (url.ToString().Contains(RequestTokenUrl)) {
callback = CallbackUrl;
} }
return oAuthWebRequestNoCheck(method, requestURL, parameters, contentType, postData);
//Generate Signature
string sig = this.GenerateSignature(uri,
this.ConsumerKey,
this.ConsumerSecret,
this.Token,
this.TokenSecret,
method.ToString(),
timeStamp,
nonce,
callback,
out outUrl,
out querystring);
if (querystring.Length > 0) {
querystring += "&";
}
querystring += OAuthSignatureKey + "=" + NetworkHelper.UrlEncode(sig);
if (querystring.Length > 0) {
outUrl += "?";
}
return WebRequest(method, outUrl + querystring, postData);
} }
/// <summary> public string oAuthWebRequestNoCheck(HTTPMethod method, string requestURL, IDictionary<string, string> parameters) {
/// Submit a web request using oAuth. return oAuthWebRequestNoCheck(method, requestURL, parameters, null, null);
/// </summary> }
/// <param name="method">GET or POST</param>
/// <param name="url">The full url, including the querystring.</param>
/// <param name="postData">Data to post (querystring format)</param>
/// <returns>The web server response.</returns>
public string oAuthWebRequest(Method method, string url, string postData) {
string outUrl = "";
string querystring = "";
string ret = "";
//Setup postData for signing. private string oAuthWebRequestNoCheck(HTTPMethod method, string requestURL, IDictionary<string, string> parameters, string contentType, MemoryStream postData) {
//Add the postData to the querystring. // Build the signature base
if (method == Method.POST) { StringBuilder signatureBase = new StringBuilder();
if (postData.Length > 0) {
//Decode the parameters and re-encode using the oAuth UrlEncode method.
NameValueCollection qs = NetworkHelper.ParseQueryString(postData);
postData = "";
foreach (string key in qs.AllKeys) {
if (postData.Length > 0) {
postData += "&";
}
qs[key] = NetworkHelper.UrlDecode(qs[key]);
qs[key] = UrlEncode3986(qs[key]);
postData += key + "=" + qs[key];
// Add Method to signature base
signatureBase.Append(method.ToString()).Append("&");
// Add normalized URL
Uri url = new Uri(requestURL);
string normalizedUrl = string.Format(System.Globalization.CultureInfo.InvariantCulture, "{0}://{1}", url.Scheme, url.Host);
if (!((url.Scheme == "http" && url.Port == 80) || (url.Scheme == "https" && url.Port == 443))) {
normalizedUrl += ":" + url.Port;
}
normalizedUrl += url.AbsolutePath;
signatureBase.Append(UrlEncode3986(normalizedUrl)).Append("&");
// Add normalized parameters
if (parameters == null) {
parameters = new Dictionary<string, string>();
}
parameters.Add(OAUTH_VERSION_KEY, OAUTH_VERSION);
parameters.Add(OAUTH_NONCE_KEY, GenerateNonce());
parameters.Add(OAUTH_TIMESTAMP_KEY, GenerateTimeStamp());
parameters.Add(OAUTH_SIGNATURE_METHOD_KEY, HMACSHA1SignatureType);
parameters.Add(OAUTH_CONSUMER_KEY_KEY, ConsumerKey);
if (CallbackUrl != null && RequestTokenUrl != null && requestURL.ToString().StartsWith(RequestTokenUrl)) {
parameters.Add(OAUTH_CALLBACK_KEY, CallbackUrl);
}
if (!string.IsNullOrEmpty(Token)) {
parameters.Add(OAUTH_TOKEN_KEY, Token);
}
signatureBase.Append(UrlEncode3986(GenerateNormalizedParametersString(parameters)));
LOG.DebugFormat("Signature base: {0}", signatureBase);
// Generate Signature and add it to the parameters
HMACSHA1 hmacsha1 = new HMACSHA1();
hmacsha1.Key = Encoding.UTF8.GetBytes(string.Format(System.Globalization.CultureInfo.InvariantCulture, "{0}&{1}", UrlEncode3986(ConsumerSecret), string.IsNullOrEmpty(TokenSecret) ? string.Empty : UrlEncode3986(TokenSecret)));
string signature = ComputeHash(hmacsha1, signatureBase.ToString());
parameters.Add(OAUTH_SIGNATURE_KEY, signature);
LOG.DebugFormat("Signature: {0}", signature);
IDictionary<string, string> requestParameters = null;
// Add oAuth values as HTTP headers, if this is allowed
StringBuilder authHeader = null;
if (HTTPMethod.POST == method && UseHTTPHeadersForAuthorization) {
authHeader = new StringBuilder();
requestParameters = new Dictionary<string, string>();
foreach (string parameterKey in parameters.Keys) {
if (parameterKey.StartsWith(OAUTH_PARAMETER_PREFIX)) {
authHeader.AppendFormat(System.Globalization.CultureInfo.InvariantCulture, "{0}=\"{1}\", ", parameterKey, UrlEncode3986(parameters[parameterKey]));
} else if (!requestParameters.ContainsKey(parameterKey)) {
LOG.DebugFormat("Request parameter: {0}={1}", parameterKey, parameters[parameterKey]);
requestParameters.Add(parameterKey, parameters[parameterKey]);
} }
if (url.IndexOf("?") > 0) { }
url += "&"; // Remove trailing comma and space and add it to the headers
} else { if (authHeader.Length > 0) {
url += "?"; authHeader.Remove(authHeader.Length - 2, 2);
}
} else if (HTTPMethod.GET == method) {
if (parameters.Count > 0) {
// Add the parameters to the request
requestURL += "?" + NetworkHelper.GenerateQueryParameters(parameters);
}
} else {
requestParameters = parameters;
}
// Create webrequest
HttpWebRequest webRequest = (HttpWebRequest)NetworkHelper.CreateWebRequest(requestURL);
webRequest.Method = method.ToString();
webRequest.ServicePoint.Expect100Continue = false;
webRequest.UserAgent = _userAgent;
webRequest.Timeout = 20000;
if (UseHTTPHeadersForAuthorization && authHeader != null) {
LOG.DebugFormat("Authorization: OAuth {0}", authHeader.ToString());
webRequest.Headers.Add("Authorization: OAuth " + authHeader.ToString());
}
if (HTTPMethod.POST == method && postData == null && requestParameters != null && requestParameters.Count > 0) {
StringBuilder form = new StringBuilder();
foreach (string parameterKey in requestParameters.Keys) {
form.AppendFormat(System.Globalization.CultureInfo.InvariantCulture, "{0}={1}&", UrlEncode3986(parameterKey), UrlEncode3986(parameters[parameterKey]));
}
// Remove trailing &
if (form.Length > 0) {
form.Remove(form.Length - 1, 1);
}
LOG.DebugFormat("Form data: {0}", form.ToString());
webRequest.ContentType = "application/x-www-form-urlencoded";
byte[] data = Encoding.UTF8.GetBytes(form.ToString());
using (var requestStream = webRequest.GetRequestStream()) {
requestStream.Write(data, 0, data.Length);
}
} else {
webRequest.ContentType = contentType;
if (postData != null) {
using (var requestStream = webRequest.GetRequestStream()) {
requestStream.Write(postData.GetBuffer(), 0, (int)postData.Length);
} }
url += postData;
} }
} }
Uri uri = new Uri(url); string responseData = WebResponseGet(webRequest);
LOG.DebugFormat("Response: {0}", responseData);
string nonce = this.GenerateNonce(); webRequest = null;
string timeStamp = this.GenerateTimeStamp();
string callback = "";
if (url.ToString().Contains(RequestTokenUrl)) {
callback = CallbackUrl;
}
//Generate Signature return responseData;
string sig = this.GenerateSignature(uri,
this.ConsumerKey,
this.ConsumerSecret,
this.Token,
this.TokenSecret,
method.ToString(),
timeStamp,
nonce,
callback,
out outUrl,
out querystring);
if (querystring.Length > 0) {
querystring += "&";
}
querystring += OAuthSignatureKey + "=" + NetworkHelper.UrlEncode(sig);
//Convert the querystring to postData
if (method == Method.POST) {
postData = querystring;
querystring = "";
}
if (querystring.Length > 0) {
outUrl += "?";
}
if (method == Method.POST || method == Method.GET) {
ret = WebRequest(method, outUrl + querystring, postData);
}
return ret;
} }
/// <summary> /// <summary>
@ -623,7 +479,7 @@ namespace GreenshotPlugin.Core {
/// <param name="url">Full url to the web resource</param> /// <param name="url">Full url to the web resource</param>
/// <param name="postData">Data to post </param> /// <param name="postData">Data to post </param>
/// <returns>The web server response.</returns> /// <returns>The web server response.</returns>
protected string WebRequest(Method method, string url, MemoryStream postData) { protected string WebRequest(HTTPMethod method, string url, string contentType, MemoryStream postData) {
HttpWebRequest webRequest = null; HttpWebRequest webRequest = null;
string responseData = ""; string responseData = "";
@ -633,6 +489,10 @@ namespace GreenshotPlugin.Core {
webRequest.UserAgent = _userAgent; webRequest.UserAgent = _userAgent;
webRequest.Timeout = 20000; webRequest.Timeout = 20000;
webRequest.ContentLength = postData.Length; webRequest.ContentLength = postData.Length;
if (method == HTTPMethod.POST) {
webRequest.ContentType = contentType;
}
using (var requestStream = webRequest.GetRequestStream()) { using (var requestStream = webRequest.GetRequestStream()) {
requestStream.Write(postData.GetBuffer(), 0, (int)postData.Length); requestStream.Write(postData.GetBuffer(), 0, (int)postData.Length);
} }
@ -644,46 +504,6 @@ namespace GreenshotPlugin.Core {
return responseData; return responseData;
} }
/// <summary>
/// Web Request Wrapper
/// </summary>
/// <param name="method">Http Method</param>
/// <param name="url">Full url to the web resource</param>
/// <param name="postData">Data to post in querystring format</param>
/// <returns>The web server response.</returns>
protected string WebRequest(Method method, string url, string postData) {
HttpWebRequest webRequest = null;
StreamWriter requestWriter = null;
string responseData = "";
webRequest = (HttpWebRequest)NetworkHelper.CreateWebRequest(url);
webRequest.Method = method.ToString();
webRequest.ServicePoint.Expect100Continue = false;
webRequest.UserAgent = _userAgent;
webRequest.Timeout = 20000;
if (method == Method.POST) {
webRequest.ContentType = "application/x-www-form-urlencoded";
requestWriter = new StreamWriter(webRequest.GetRequestStream());
try {
requestWriter.Write(postData);
} catch {
throw;
} finally {
requestWriter.Close();
requestWriter = null;
}
}
responseData = WebResponseGet(webRequest);
webRequest = null;
return responseData;
}
/// <summary> /// <summary>
/// Process the web response. /// Process the web response.
/// </summary> /// </summary>
@ -707,4 +527,5 @@ namespace GreenshotPlugin.Core {
return responseData; return responseData;
} }
} }
} }