diff --git a/GreenshotImgurPlugin/ImgurUtils.cs b/GreenshotImgurPlugin/ImgurUtils.cs
index afe8a240c..6df2f0daf 100644
--- a/GreenshotImgurPlugin/ImgurUtils.cs
+++ b/GreenshotImgurPlugin/ImgurUtils.cs
@@ -100,39 +100,34 @@ namespace GreenshotImgurPlugin {
/// byte[] with image data
/// ImgurResponse
public static ImgurInfo UploadToImgur(byte[] imageData, int dataLength, string title, string filename) {
- StringBuilder uploadRequest = new StringBuilder();
+ IDictionary uploadParameters = new Dictionary();
// Add image
- uploadRequest.Append("image=");
- uploadRequest.Append(OAuthHelper.UrlEncode3986(System.Convert.ToBase64String(imageData, 0, dataLength)));
+ uploadParameters.Add("image", System.Convert.ToBase64String(imageData, 0, dataLength));
// add type
- uploadRequest.Append("&type=base64");
+ uploadParameters.Add("type", "base64");
// add title
if (title != null) {
- uploadRequest.Append("&title=");
- uploadRequest.Append(OAuthHelper.UrlEncode3986(title));
+ uploadParameters.Add("title", title);
}
// add filename
if (filename != null) {
- uploadRequest.Append("&name=");
- uploadRequest.Append(OAuthHelper.UrlEncode3986(filename));
+ uploadParameters.Add("name", filename);
}
- string url;
- string responseString;
+ string responseString = null;
if (config.AnonymousAccess) {
// add key
- uploadRequest.Append("&key=");
- uploadRequest.Append(IMGUR_ANONYMOUS_API_KEY);
- url = config.ImgurApiUrl + "/upload";
- HttpWebRequest webRequest = (HttpWebRequest)NetworkHelper.CreateWebRequest(url);
+ uploadParameters.Add("key", IMGUR_ANONYMOUS_API_KEY);
+ HttpWebRequest webRequest = (HttpWebRequest)NetworkHelper.CreateWebRequest(config.ImgurApiUrl + "/upload");
webRequest.Method = "POST";
webRequest.ContentType = "application/x-www-form-urlencoded";
webRequest.ServicePoint.Expect100Continue = false;
using(StreamWriter streamWriter = new StreamWriter(webRequest.GetRequestStream())) {
- streamWriter.Write(uploadRequest.ToString());
+ string urloadText = NetworkHelper.GenerateQueryParameters(uploadParameters);
+ streamWriter.Write(urloadText);
}
using (WebResponse response = webRequest.GetResponse()) {
LogCredits(response);
@@ -142,37 +137,38 @@ namespace GreenshotImgurPlugin {
}
} else {
- url = config.ImgurApiUrl + "/account/images";
- OAuthHelper oAuth = new OAuthHelper();
+ OAuthSession oAuth = new OAuthSession();
oAuth.BrowserWidth = 650;
oAuth.BrowserHeight = 500;
oAuth.CallbackUrl = "http://getgreenshot.org";
oAuth.AccessTokenUrl = "http://api.imgur.com/oauth/access_token";
oAuth.AuthorizeUrl = "http://api.imgur.com/oauth/authorize";
oAuth.RequestTokenUrl = "http://api.imgur.com/oauth/request_token";
- oAuth.ConsumerKey = ImgurCredentials.CONSUMER_KEY;
- oAuth.ConsumerSecret = ImgurCredentials.CONSUMER_SECRET;
+ oAuth.ConsumerKey = "907d4455b8c38144d68c4f72190af4c40504a0ac7";
+ oAuth.ConsumerSecret = "d33902ef409fea163ab755454c15b3d0";
oAuth.UserAgent = "Greenshot";
- if (string.IsNullOrEmpty(config.ImgurToken)) {
- LOG.Debug("Creating Imgur Token");
- oAuth.getRequestToken();
- if (string.IsNullOrEmpty(oAuth.authorizeToken("Imgur authorization"))) {
- LOG.Debug("User didn't authenticate!");
- return null;
+ oAuth.LoginTitle = "Imgur authorization";
+ //oAuth.UseHTTPHeadersForAuthorization = false;
+ oAuth.Token = config.ImgurToken;
+ oAuth.TokenSecret = config.ImgurTokenSecret;
+ try {
+ 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();
- config.ImgurToken = oAuth.Token;
- config.ImgurTokenSecret = oAuth.TokenSecret;
- } else {
- LOG.Debug("Using stored Imgur Token");
- oAuth.Token = config.ImgurToken;
- oAuth.TokenSecret = config.ImgurTokenSecret;
+ if (oAuth.TokenSecret != null) {
+ config.ImgurTokenSecret = oAuth.TokenSecret;
+ }
+ IniConfig.Save();
}
- responseString = oAuth.oAuthWebRequest(OAuthHelper.Method.POST, url, uploadRequest.ToString());
}
LOG.Info(responseString);
ImgurInfo imgurInfo = ImgurInfo.ParseResponse(responseString);
- LOG.Debug("Upload to imgur was finished");
return imgurInfo;
}
diff --git a/GreenshotPhotobucketPlugin/PhotobucketUtils.cs b/GreenshotPhotobucketPlugin/PhotobucketUtils.cs
index 106d9293d..15e5637ce 100644
--- a/GreenshotPhotobucketPlugin/PhotobucketUtils.cs
+++ b/GreenshotPhotobucketPlugin/PhotobucketUtils.cs
@@ -48,59 +48,39 @@ namespace GreenshotPhotobucketPlugin {
/// byte[] with image data
/// PhotobucketResponse
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;
- OAuthHelper oAuth = new OAuthHelper();
+ OAuthSession oAuth = new OAuthSession();
// This url is configured in the Photobucket API settings in the Photobucket site!!
oAuth.CallbackUrl = "http://getgreenshot.org";
oAuth.AccessTokenUrl = "http://api.photobucket.com/login/access";
oAuth.AuthorizeUrl = "http://photobucket.com/apilogin/login";
oAuth.RequestTokenUrl = "http://api.photobucket.com/login/request";
- oAuth.ConsumerKey = ;
- oAuth.ConsumerSecret = ;
+ oAuth.ConsumerKey = "149833145";
+ oAuth.ConsumerSecret = "ebd828180b11103c010c7e71c66f6bcb";
oAuth.UserAgent = "Greenshot";
oAuth.BrowserWidth = 1010;
oAuth.BrowserHeight = 400;
oAuth.CheckVerifier = false;
- if (string.IsNullOrEmpty(config.PhotobucketToken)) {
- LOG.Debug("Creating Photobucket Token");
- try {
- oAuth.getRequestToken();
- } catch (Exception ex) {
- LOG.Error(ex);
- throw new NotSupportedException("Photobucket is not available: " + ex.Message);
- }
- LOG.Debug("Authorizing Photobucket");
- if (string.IsNullOrEmpty(oAuth.authorizeToken("Photobucket authorization"))) {
- return null;
- }
- 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;
+ oAuth.LoginTitle = "Photobucket authorization";
+ Dictionary parameters = new Dictionary();
+ // add album
+ parameters.Add("identifier", "greenshot");
+ // add type
+ parameters.Add("type", "base64");
+ // Add image
+ parameters.Add("uploadfile", System.Convert.ToBase64String(imageData, 0, dataLength));
+ // add title
+ if (title != null) {
+ parameters.Add("title", title);
}
- 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);
PhotobucketInfo PhotobucketInfo = PhotobucketInfo.ParseResponse(responseString);
LOG.Debug("Upload to Photobucket was finished");
diff --git a/GreenshotPlugin/Controls/OAuthLoginForm.cs b/GreenshotPlugin/Controls/OAuthLoginForm.cs
index 2de8d2460..f1b2d786d 100644
--- a/GreenshotPlugin/Controls/OAuthLoginForm.cs
+++ b/GreenshotPlugin/Controls/OAuthLoginForm.cs
@@ -34,7 +34,7 @@ namespace GreenshotPlugin.Controls {
///
public partial class OAuthLoginForm : Form {
private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(OAuthLoginForm));
- private OAuthHelper _oauth;
+ private OAuthSession _oauthSession;
private String _token;
private String _verifier;
private String _tokenSecret;
@@ -57,18 +57,18 @@ namespace GreenshotPlugin.Controls {
}
}
- public OAuthLoginForm(OAuthHelper o, string browserTitle, int width, int height) {
- _oauth = o;
+ public OAuthLoginForm(OAuthSession o, string browserTitle, int width, int height) {
+ _oauthSession = o;
_token = null;
InitializeComponent();
this.ClientSize = new System.Drawing.Size(width, height);
this.Icon = GreenshotPlugin.Core.GreenshotResources.getGreenshotIcon();
this.Text = browserTitle;
this.addressTextBox.Text = o.AuthorizationLink;
- _token = _oauth.Token;
- _tokenSecret = _oauth.TokenSecret;
+ _token = _oauthSession.Token;
+ _tokenSecret = _oauthSession.TokenSecret;
browser.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(browser_DocumentCompleted);
- browser.Navigate(new Uri(_oauth.AuthorizationLink));
+ browser.Navigate(new Uri(_oauthSession.AuthorizationLink));
WindowDetails.ToForeground(this.Handle);
}
@@ -88,15 +88,15 @@ namespace GreenshotPlugin.Controls {
}
private void checkUrl() {
- if (browser.Url.ToString().StartsWith(_oauth.CallbackUrl)) {
+ if (browser.Url.ToString().StartsWith(_oauthSession.CallbackUrl)) {
string queryParams = browser.Url.Query;
if (queryParams.Length > 0) {
//Store the Token and Token Secret
- NameValueCollection qs = NetworkHelper.ParseQueryString(queryParams);
- if (qs["oauth_token"] != null) {
+ IDictionary qs = NetworkHelper.ParseQueryString(queryParams);
+ if (qs.ContainsKey("oauth_token") && qs["oauth_token"] != null) {
_token = qs["oauth_token"];
}
- if (qs["oauth_verifier"] != null) {
+ if (qs.ContainsKey("oauth_verifier") && qs["oauth_verifier"] != null) {
_verifier = qs["oauth_verifier"];
}
}
diff --git a/GreenshotPlugin/Core/NetworkHelper.cs b/GreenshotPlugin/Core/NetworkHelper.cs
index 3f34a63cb..bf2b3db00 100644
--- a/GreenshotPlugin/Core/NetworkHelper.cs
+++ b/GreenshotPlugin/Core/NetworkHelper.cs
@@ -23,11 +23,13 @@ using System.Drawing;
using System.IO;
using System.Net;
using System.Text;
+using System.Collections.Generic;
using System.Collections.Specialized;
using System.Text.RegularExpressions;
using Greenshot.IniFile;
using System.Security.Cryptography.X509Certificates;
using System.Net.Security;
+using System.Web;
namespace GreenshotPlugin.Core {
///
@@ -158,6 +160,26 @@ namespace GreenshotPlugin.Core {
return null;
}
+ ///
+ /// 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
+ ///
+ ///
+ /// escaped data string
+ 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;
+ }
+
///
/// UrlDecodes a string without requiring System.Web
///
@@ -174,23 +196,50 @@ namespace GreenshotPlugin.Core {
/// ParseQueryString without the requirement for System.Web
///
///
- ///
- public static NameValueCollection ParseQueryString(string s) {
- NameValueCollection nvc = new NameValueCollection();
+ /// Dictionary
+ public static IDictionary ParseQueryString(string s) {
+ IDictionary parameters = new SortedDictionary();
// remove anything other than query string from url
if (s.Contains("?")) {
s = s.Substring(s.IndexOf('?') + 1);
}
foreach (string vp in Regex.Split(s, "&")) {
+ if (string.IsNullOrEmpty(vp)) {
+ continue;
+ }
string[] singlePair = Regex.Split(vp, "=");
+ if (parameters.ContainsKey(singlePair[0])) {
+ parameters.Remove(singlePair[0]);
+ }
if (singlePair.Length == 2) {
- nvc.Add(singlePair[0], singlePair[1]);
+ parameters.Add(singlePair[0], singlePair[1]);
} else {
// 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;
}
+
+ ///
+ /// Generate the query paramters
+ ///
+ /// the list of query parameters
+ /// a string with the query parameters
+ public static string GenerateQueryParameters(IDictionary queryParameters) {
+ if (queryParameters == null || queryParameters.Count == 0) {
+ return string.Empty;
+ }
+
+ queryParameters = new SortedDictionary(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();
+ }
}
}
diff --git a/GreenshotPlugin/Core/OAuthHelper.cs b/GreenshotPlugin/Core/OAuthHelper.cs
index abf48a1dd..23d5e686c 100644
--- a/GreenshotPlugin/Core/OAuthHelper.cs
+++ b/GreenshotPlugin/Core/OAuthHelper.cs
@@ -29,88 +29,56 @@ using System.Text.RegularExpressions;
using GreenshotPlugin.Controls;
namespace GreenshotPlugin.Core {
- public class OAuthHelper {
- private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(OAuthHelper));
- ///
- /// Provides a predefined set of algorithms that are supported officially by the protocol
- ///
- protected enum SignatureTypes {
- HMACSHA1,
- PLAINTEXT,
- RSASHA1
- }
+ ///
+ /// Provides a predefined set of algorithms that are supported officially by the protocol
+ ///
+ public enum OAuthSignatureTypes {
+ HMACSHA1,
+ PLAINTEXT,
+ RSASHA1
+ }
+
+ public enum HTTPMethod { GET, POST, PUT, DELETE };
- ///
- /// Provides an internal structure to sort the query parameter
- ///
- protected class QueryParameter {
- 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; }
- }
- }
-
- ///
- /// Comparer class used to perform the sorting of the query parameters
- ///
- protected class QueryParameterComparer : IComparer {
-
- #region IComparer 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_";
+ public class OAuthSession {
+ private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(OAuthSession));
+ protected const string OAUTH_VERSION = "1.0";
+ protected const string OAUTH_PARAMETER_PREFIX = "oauth_";
//
// List of know and used oauth parameters' names
//
- protected const string OAuthConsumerKeyKey = "oauth_consumer_key";
- protected const string OAuthCallbackKey = "oauth_callback";
- protected const string OAuthVersionKey = "oauth_version";
- protected const string OAuthSignatureMethodKey = "oauth_signature_method";
- protected const string OAuthSignatureKey = "oauth_signature";
- protected const string OAuthTimestampKey = "oauth_timestamp";
- protected const string OAuthNonceKey = "oauth_nonce";
- protected const string OAuthTokenKey = "oauth_token";
- protected const string oAauthVerifierKey = "oauth_verifier";
- protected const string OAuthTokenSecretKey = "oauth_token_secret";
+ protected const string OAUTH_CONSUMER_KEY_KEY = "oauth_consumer_key";
+ protected const string OAUTH_CALLBACK_KEY = "oauth_callback";
+ protected const string OAUTH_VERSION_KEY = "oauth_version";
+ protected const string OAUTH_SIGNATURE_METHOD_KEY = "oauth_signature_method";
+ protected const string OAUTH_TIMESTAMP_KEY = "oauth_timestamp";
+ protected const string OAUTH_NONCE_KEY = "oauth_nonce";
+ protected const string OAUTH_TOKEN_KEY = "oauth_token";
+ protected const string OAUTH_VERIFIER_KEY = "oauth_verifier";
+ protected const string OAUTH_TOKEN_SECRET_KEY = "oauth_token_secret";
+ protected const string OAUTH_SIGNATURE_KEY = "oauth_signature";
protected const string HMACSHA1SignatureType = "HMAC-SHA1";
protected const string PlainTextSignatureType = "PLAINTEXT";
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 _callbackUrl = "http://getgreenshot.org";
private bool checkVerifier = true;
+ private bool useHTTPHeadersForAuthorization = true;
+ private bool useAuthorization = true;
+
// default browser size
private int _browserWidth = 864;
private int _browserHeight = 587;
-
+ private string loginTitle = "Authorize Greenshot access";
+
#region PublicPropertiies
public string ConsumerKey { get; set; }
public string ConsumerSecret { get; set; }
@@ -149,15 +117,36 @@ namespace GreenshotPlugin.Core {
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
-
- 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-_.~";
///
/// Helper function to compute a hash value
@@ -165,7 +154,7 @@ namespace GreenshotPlugin.Core {
/// 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
/// The data to hash
/// a Base64 string of the hash value
- private string ComputeHash(HashAlgorithm hashAlgorithm, string data) {
+ private static string ComputeHash(HashAlgorithm hashAlgorithm, string data) {
if (hashAlgorithm == null) {
throw new ArgumentNullException("hashAlgorithm");
}
@@ -174,56 +163,31 @@ namespace GreenshotPlugin.Core {
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);
return Convert.ToBase64String(hashBytes);
}
///
- /// Internal function to cut out all non oauth query string parameters (all parameters not begining with "oauth_")
+ /// Generate the normalized paramter string
///
- /// The query string part of the Url
- /// A list of QueryParameter each containing the parameter name and value
- private List GetQueryParameters(string parameters) {
- if (parameters.StartsWith("?")) {
- parameters = parameters.Remove(0, 1);
+ /// the list of query parameters
+ /// a string with the normalized query parameters
+ private static string GenerateNormalizedParametersString(IDictionary queryParameters) {
+ if (queryParameters == null || queryParameters.Count == 0) {
+ return string.Empty;
}
- List result = new List();
+ queryParameters = new SortedDictionary(queryParameters);
- if (!string.IsNullOrEmpty(parameters)) {
- string[] p = parameters.Split('&');
- foreach (string s in p) {
- 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));
- }
- }
- }
+ StringBuilder sb = new StringBuilder();
+ foreach (string key in queryParameters.Keys) {
+ sb.AppendFormat(System.Globalization.CultureInfo.InvariantCulture, "{0}={1}&", key, UrlEncode3986(queryParameters[key]));
}
+ sb.Remove(sb.Length - 1, 1);
- return result;
- }
-
- ///
- /// 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
- ///
- ///
- /// escaped data string
- 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;
+ return sb.ToString();
}
///
@@ -232,170 +196,26 @@ namespace GreenshotPlugin.Core {
///
/// The value to Url encode
/// Returns a Url encoded string
- public static string UrlEncode3986(string text) {
- string[] UriRfc3986CharsToEscape = new[] { "!", "*", "'", "(", ")" };
- LOG.DebugFormat("Text size {0}", text.Length);
- StringBuilder escaped = EscapeDataStringToStringBuilder(text);
+ /// This will cause an ignorable CA1055 warning in code analysis.
+ private static string UrlEncode3986(string value) {
+ StringBuilder result = new StringBuilder();
- for (int i = 0; i < UriRfc3986CharsToEscape.Length; i++) {
- escaped.Replace(UriRfc3986CharsToEscape[i], Uri.HexEscape(UriRfc3986CharsToEscape[i][0]));
- }
- return escaped.ToString();
- }
- ///
- /// Normalizes the request parameters according to the spec
- ///
- /// The list of parameters already sorted
- /// a string representing the normalized parameters
- protected string NormalizeRequestParameters(IList 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("&");
+ foreach (char symbol in value) {
+ if (UNRESERVED_CHARS.IndexOf(symbol) != -1) {
+ result.Append(symbol);
+ } else {
+ result.Append('%' + String.Format(System.Globalization.CultureInfo.InvariantCulture, "{0:X2}", (int)symbol));
}
}
- return sb.ToString();
- }
-
- ///
- /// Generate the signature base that is used to produce the signature
- ///
- /// The full url that needs to be signed including its non OAuth url parameters
- /// The consumer key
- /// The token, if available. If not available pass null or an empty string
- /// The token secret, if available. If not available pass null or an empty string
- /// The http method used. Must be a valid HTTP method verb (POST,GET,PUT, etc)
- /// The signature type. To use the default values use OAuthBase.SignatureTypes.
- /// The signature base
- 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 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();
- }
-
- ///
- /// Generate the signature value based on the given signature base and hash algorithm
- ///
- /// The signature based as produced by the GenerateSignatureBase method or by any other means
- /// 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
- /// A base64 string of the hash value
- protected string GenerateSignatureUsingHash(string signatureBase, HashAlgorithm hash) {
- return ComputeHash(hash, signatureBase);
- }
-
- ///
- /// Generates a signature using the HMAC-SHA1 algorithm
- ///
- /// The full url that needs to be signed including its non OAuth url parameters
- /// The consumer key
- /// The consumer seceret
- /// The token, if available. If not available pass null or an empty string
- /// The token secret, if available. If not available pass null or an empty string
- /// The http method used. Must be a valid HTTP method verb (POST,GET,PUT, etc)
- /// A base64 string of the hash value
- 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);
- }
-
- ///
- /// Generates a signature using the specified signatureType
- ///
- /// The full url that needs to be signed including its non OAuth url parameters
- /// The consumer key
- /// The consumer seceret
- /// The token, if available. If not available pass null or an empty string
- /// The token secret, if available. If not available pass null or an empty string
- /// The http method used. Must be a valid HTTP method verb (POST,GET,PUT, etc)
- /// The type of signature to use
- /// A base64 string of the hash value
- 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");
- }
+ return result.ToString();
}
///
/// Generate the timestamp for the signature
///
///
-
- protected virtual string GenerateTimeStamp() {
+ public static string GenerateTimeStamp() {
// Default implementation of UNIX time of the current UTC time
TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
return Convert.ToInt64(ts.TotalSeconds).ToString();
@@ -405,23 +225,22 @@ namespace GreenshotPlugin.Core {
/// Generate a nonce
///
///
- protected virtual string GenerateNonce() {
+ public static string GenerateNonce() {
// Just a simple implementation of a random number between 123400 and 9999999
return random.Next(123400, 9999999).ToString();
}
-
///
/// Get the request token using the consumer key and secret. Also initializes tokensecret
///
/// The request token.
- public String getRequestToken() {
+ private String getRequestToken() {
string ret = null;
- string response = oAuthWebRequest(Method.POST, RequestTokenUrl, String.Empty);
+ string response = oAuthWebRequestNoCheck(HTTPMethod.POST, RequestTokenUrl, null);
if (response.Length > 0) {
- NameValueCollection qs = NetworkHelper.ParseQueryString(response);
- if (qs[OAuthTokenKey] != null) {
- this.Token = qs[OAuthTokenKey];
- this.TokenSecret = qs[OAuthTokenSecretKey];
+ IDictionary qs = NetworkHelper.ParseQueryString(response);
+ if (qs.ContainsKey(OAUTH_TOKEN_KEY)) {
+ this.Token = qs[OAUTH_TOKEN_KEY];
+ this.TokenSecret = qs[OAUTH_TOKEN_SECRET_KEY];
ret = this.Token;
}
}
@@ -432,13 +251,13 @@ namespace GreenshotPlugin.Core {
/// Authorize the token by showing the dialog
///
/// The request token.
- public String authorizeToken(string browserTitle) {
+ private String authorizeToken() {
if (string.IsNullOrEmpty(Token)) {
Exception e = new Exception("The request token is not set");
throw e;
}
LOG.DebugFormat("Opening AuthorizationLink: {0}", AuthorizationLink);
- OAuthLoginForm oAuthLoginForm = new OAuthLoginForm(this, browserTitle, BrowserWidth, BrowserHeight);
+ OAuthLoginForm oAuthLoginForm = new OAuthLoginForm(this, LoginTitle, BrowserWidth, BrowserHeight);
oAuthLoginForm.ShowDialog();
Token = oAuthLoginForm.Token;
if (CheckVerifier) {
@@ -457,163 +276,200 @@ namespace GreenshotPlugin.Core {
/// Get the access token
///
/// The access token.
- public String getAccessToken() {
+ private String getAccessToken() {
if (string.IsNullOrEmpty(Token) || (CheckVerifier && string.IsNullOrEmpty(Verifier))) {
Exception e = new Exception("The request token and verifier were not set");
throw e;
}
- string response = oAuthWebRequest(Method.POST, AccessTokenUrl, string.Empty);
+ string response = oAuthWebRequestNoCheck(HTTPMethod.POST, AccessTokenUrl, null);
if (response.Length > 0) {
- NameValueCollection qs = NetworkHelper.ParseQueryString(response);
- if (qs[OAuthTokenKey] != null) {
- this.Token = qs[OAuthTokenKey];
+ IDictionary qs = NetworkHelper.ParseQueryString(response);
+ if (qs.ContainsKey(OAUTH_TOKEN_KEY) && qs[OAUTH_TOKEN_KEY] != null) {
+ this.Token = qs[OAUTH_TOKEN_KEY];
}
- if (qs[OAuthTokenSecretKey] != null) {
- this.TokenSecret = qs[OAuthTokenSecretKey];
+ if (qs.ContainsKey(OAUTH_TOKEN_SECRET_KEY) && qs[OAUTH_TOKEN_SECRET_KEY] != null) {
+ this.TokenSecret = qs[OAUTH_TOKEN_SECRET_KEY];
}
}
return Token;
}
+ ///
+ /// This method goes through the whole authorize process, including a Authorization window.
+ ///
+ /// true if the process is completed
+ 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;
+ }
+
///
/// Get the link to the authorization page for this application.
///
/// The url with a valid request token, or a null string.
public string AuthorizationLink {
get {
- return AuthorizeUrl + "?" + OAuthTokenKey + "=" + this.Token + "&" + OAuthCallbackKey + "=" + UrlEncode3986(CallbackUrl);
+ return AuthorizeUrl + "?" + OAUTH_TOKEN_KEY + "=" + this.Token + "&" + OAUTH_CALLBACK_KEY + "=" + UrlEncode3986(CallbackUrl);
}
}
+ ///
+ /// Wrapper
+ ///
+ ///
+ ///
+ ///
+ ///
+ public string oAuthWebRequest(HTTPMethod method, string requestURL, IDictionary parameters) {
+ return oAuthWebRequest(method, requestURL, parameters, null, null);
+ }
///
/// Submit a web request using oAuth.
///
/// GET or POST
- /// The full url, including the querystring.
+ /// The full url, including the querystring.
+ /// Parameters for the request
+ /// contenttype for the postdata
/// Data to post (MemoryStream)
/// The web server response.
- public string oAuthWebRequest(Method method, string url, MemoryStream postData) {
- string outUrl = "";
- string querystring = "";
-
- Uri uri = new Uri(url);
-
- string nonce = this.GenerateNonce();
- string timeStamp = this.GenerateTimeStamp();
-
- string callback = "";
- if (url.ToString().Contains(RequestTokenUrl)) {
- callback = CallbackUrl;
+ public string oAuthWebRequest(HTTPMethod method, string requestURL, IDictionary parameters, string contentType, MemoryStream postData) {
+ // If we are not trying to get a Authorization or Accestoken, and we don't have a token, create one
+ if (string.IsNullOrEmpty(Token)) {
+ if (!authorize()) {
+ throw new Exception("Not authorized");
+ }
}
-
- //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);
+ return oAuthWebRequestNoCheck(method, requestURL, parameters, contentType, postData);
}
- ///
- /// Submit a web request using oAuth.
- ///
- /// GET or POST
- /// The full url, including the querystring.
- /// Data to post (querystring format)
- /// The web server response.
- public string oAuthWebRequest(Method method, string url, string postData) {
- string outUrl = "";
- string querystring = "";
- string ret = "";
+ public string oAuthWebRequestNoCheck(HTTPMethod method, string requestURL, IDictionary parameters) {
+ return oAuthWebRequestNoCheck(method, requestURL, parameters, null, null);
+ }
- //Setup postData for signing.
- //Add the postData to the querystring.
- if (method == Method.POST) {
- 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];
+ private string oAuthWebRequestNoCheck(HTTPMethod method, string requestURL, IDictionary parameters, string contentType, MemoryStream postData) {
+ // Build the signature base
+ StringBuilder signatureBase = new StringBuilder();
+ // 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();
+ }
+
+ 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 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();
+ 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 += "&";
- } else {
- url += "?";
+ }
+ // Remove trailing comma and space and add it to the headers
+ if (authHeader.Length > 0) {
+ 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();
- string timeStamp = this.GenerateTimeStamp();
-
- string callback = "";
- if (url.ToString().Contains(RequestTokenUrl)) {
- callback = CallbackUrl;
- }
+ webRequest = null;
- //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);
-
- //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;
+ return responseData;
}
///
@@ -623,7 +479,7 @@ namespace GreenshotPlugin.Core {
/// Full url to the web resource
/// Data to post
/// The web server response.
- protected string WebRequest(Method method, string url, MemoryStream postData) {
+ protected string WebRequest(HTTPMethod method, string url, string contentType, MemoryStream postData) {
HttpWebRequest webRequest = null;
string responseData = "";
@@ -633,6 +489,10 @@ namespace GreenshotPlugin.Core {
webRequest.UserAgent = _userAgent;
webRequest.Timeout = 20000;
webRequest.ContentLength = postData.Length;
+ if (method == HTTPMethod.POST) {
+ webRequest.ContentType = contentType;
+ }
+
using (var requestStream = webRequest.GetRequestStream()) {
requestStream.Write(postData.GetBuffer(), 0, (int)postData.Length);
}
@@ -644,46 +504,6 @@ namespace GreenshotPlugin.Core {
return responseData;
}
- ///
- /// Web Request Wrapper
- ///
- /// Http Method
- /// Full url to the web resource
- /// Data to post in querystring format
- /// The web server response.
- 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;
-
- }
-
///
/// Process the web response.
///
@@ -707,4 +527,5 @@ namespace GreenshotPlugin.Core {
return responseData;
}
}
+
}