Reused new OAuth 2 code for the Box plug-in, this was possible by adding the embedded browser. Also refactored code to be more readable, and have more reuse. Fixed problems with Picasa upload and pressing cancel on the PleaseWaitForm. [skip ci]

This commit is contained in:
Robin 2015-04-17 15:44:27 +02:00
parent 9d7299e5ea
commit 1f80d56b10
16 changed files with 408 additions and 277 deletions

View file

@ -31,7 +31,7 @@ namespace Greenshot.Forms {
// The InitializeComponent() call is required for Windows Forms designer support. // The InitializeComponent() call is required for Windows Forms designer support.
// //
InitializeComponent(); InitializeComponent();
BringToFront = true; ToFront = true;
} }
public BugReportForm(string bugText) : this() { public BugReportForm(string bugText) : this() {

View file

@ -177,7 +177,7 @@ namespace Greenshot.Forms {
ResumeLayout(); ResumeLayout();
// Fix missing focus // Fix missing focus
BringToFront = true; ToFront = true;
TopMost = true; TopMost = true;
} }

View file

@ -1,10 +1,22 @@
/* /*
* Created by SharpDevelop. * Greenshot - a free and open source screenshot tool
* User: jens * Copyright (C) 2007-2015 Thomas Braun, Jens Klingen, Robin Krom
* Date: 09.04.2012
* Time: 19:24
* *
* To change this template use Tools | Options | Coding | Edit Standard Headers. * For more information see: http://getgreenshot.org/
* The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
using GreenshotPlugin.Core; using GreenshotPlugin.Core;
@ -28,7 +40,7 @@ namespace Greenshot.Help
} }
public static void LoadHelp() { public static void LoadHelp() {
string uri = findOnlineHelpUrl(Language.CurrentLanguage); string uri = FindOnlineHelpUrl(Language.CurrentLanguage);
if(uri == null) { if(uri == null) {
uri = Language.HelpFilePath; uri = Language.HelpFilePath;
} }
@ -36,7 +48,7 @@ namespace Greenshot.Help
} }
/// <returns>URL of help file in selected ietf, or (if not present) default ietf, or null (if not present, too. probably indicating that there is no internet connection)</returns> /// <returns>URL of help file in selected ietf, or (if not present) default ietf, or null (if not present, too. probably indicating that there is no internet connection)</returns>
private static string findOnlineHelpUrl(string currentIETF) { private static string FindOnlineHelpUrl(string currentIETF) {
string ret = null; string ret = null;
string extHelpUrlForCurrrentIETF = EXT_HELP_URL; string extHelpUrlForCurrrentIETF = EXT_HELP_URL;
@ -45,12 +57,12 @@ namespace Greenshot.Help
extHelpUrlForCurrrentIETF += currentIETF.ToLower() + "/"; extHelpUrlForCurrrentIETF += currentIETF.ToLower() + "/";
} }
HttpStatusCode? httpStatusCode = getHttpStatus(extHelpUrlForCurrrentIETF); HttpStatusCode? httpStatusCode = GetHttpStatus(extHelpUrlForCurrrentIETF);
if(httpStatusCode == HttpStatusCode.OK) { if(httpStatusCode == HttpStatusCode.OK) {
ret = extHelpUrlForCurrrentIETF; ret = extHelpUrlForCurrrentIETF;
} else if(httpStatusCode != null && !extHelpUrlForCurrrentIETF.Equals(EXT_HELP_URL)) { } else if(httpStatusCode != null && !extHelpUrlForCurrrentIETF.Equals(EXT_HELP_URL)) {
LOG.DebugFormat("Localized online help not found at {0}, will try {1} as fallback", extHelpUrlForCurrrentIETF, EXT_HELP_URL); LOG.DebugFormat("Localized online help not found at {0}, will try {1} as fallback", extHelpUrlForCurrrentIETF, EXT_HELP_URL);
httpStatusCode = getHttpStatus(EXT_HELP_URL); httpStatusCode = GetHttpStatus(EXT_HELP_URL);
if(httpStatusCode == HttpStatusCode.OK) { if(httpStatusCode == HttpStatusCode.OK) {
ret = EXT_HELP_URL; ret = EXT_HELP_URL;
} else { } else {
@ -68,9 +80,9 @@ namespace Greenshot.Help
/// </summary> /// </summary>
/// <param name="url">URL for which the HTTP status is to be checked</param> /// <param name="url">URL for which the HTTP status is to be checked</param>
/// <returns>An HTTP status code, or null if there is none (probably indicating that there is no internet connection available</returns> /// <returns>An HTTP status code, or null if there is none (probably indicating that there is no internet connection available</returns>
private static HttpStatusCode? getHttpStatus(string url) { private static HttpStatusCode? GetHttpStatus(string url) {
try { try {
HttpWebRequest req = (HttpWebRequest)NetworkHelper.CreateWebRequest(url); HttpWebRequest req = NetworkHelper.CreateWebRequest(url);
HttpWebResponse res = (HttpWebResponse)req.GetResponse(); HttpWebResponse res = (HttpWebResponse)req.GetResponse();
return res.StatusCode; return res.StatusCode;
} catch(WebException e) { } catch(WebException e) {

View file

@ -18,9 +18,11 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
using System.Windows.Forms; using System.Windows.Forms;
using Greenshot.IniFile; using Greenshot.IniFile;
using GreenshotPlugin.Core; using GreenshotPlugin.Core;
using System;
namespace GreenshotBoxPlugin { namespace GreenshotBoxPlugin {
/// <summary> /// <summary>
@ -38,10 +40,43 @@ namespace GreenshotBoxPlugin {
public bool AfterUploadLinkToClipBoard; public bool AfterUploadLinkToClipBoard;
[IniProperty("UseSharedLink", Description = "Use the shared link, instead of the private, on the clipboard", DefaultValue = "True")] [IniProperty("UseSharedLink", Description = "Use the shared link, instead of the private, on the clipboard", DefaultValue = "True")]
public bool UseSharedLink; public bool UseSharedLink {
get;
set;
}
[IniProperty("FolderId", Description = "Folder ID to upload to, only change if you know what you are doing!", DefaultValue = "0")]
public string FolderId {
get;
set;
}
[IniProperty("BoxToken", Description = "Token.", DefaultValue = "")] [IniProperty("AddFilename", Description = "Is the filename passed on to Box", DefaultValue = "False")]
public string BoxToken; public bool AddFilename {
get;
set;
}
[IniProperty("RefreshToken", Description = "Box authorization refresh Token", Encrypted = true)]
public string RefreshToken {
get;
set;
}
/// <summary>
/// Not stored
/// </summary>
public string AccessToken {
get;
set;
}
/// <summary>
/// Not stored
/// </summary>
public DateTimeOffset AccessTokenExpires {
get;
set;
}
/// <summary> /// <summary>
/// A form for token /// A form for token

View file

@ -18,16 +18,14 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
using System;
using Greenshot.IniFile;
using GreenshotPlugin.Core;
using System.Collections.Generic; using System.Collections.Generic;
using System.Drawing; using System.Drawing;
using System.Net;
using System.Text;
using Greenshot.IniFile;
using GreenshotPlugin.Controls;
using GreenshotPlugin.Core;
using System.Runtime.Serialization.Json;
using System.IO; using System.IO;
using System.Runtime.Serialization.Json;
using System.Text;
namespace GreenshotBoxPlugin { namespace GreenshotBoxPlugin {
@ -37,101 +35,24 @@ namespace GreenshotBoxPlugin {
public static class BoxUtils { public static class BoxUtils {
private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(BoxUtils)); private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(BoxUtils));
private static readonly BoxConfiguration Config = IniConfig.GetIniSection<BoxConfiguration>(); private static readonly BoxConfiguration Config = IniConfig.GetIniSection<BoxConfiguration>();
private const string RedirectUri = "https://www.box.com/home/";
private const string UploadFileUri = "https://upload.box.com/api/2.0/files/content"; private const string UploadFileUri = "https://upload.box.com/api/2.0/files/content";
private const string AuthorizeUri = "https://www.box.com/api/oauth2/authorize";
private const string TokenUri = "https://www.box.com/api/oauth2/token";
private const string FilesUri = "https://www.box.com/api/2.0/files/{0}"; private const string FilesUri = "https://www.box.com/api/2.0/files/{0}";
private static bool Authorize() {
string authorizeUrl = string.Format("{0}?client_id={1}&response_type=code&state=dropboxplugin&redirect_uri={2}", AuthorizeUri, BoxCredentials.ClientId, RedirectUri);
OAuthLoginForm loginForm = new OAuthLoginForm("Box Authorize", new Size(1060, 600), authorizeUrl, RedirectUri);
loginForm.ShowDialog();
if (!loginForm.isOk) {
return false;
}
var callbackParameters = loginForm.CallbackParameters;
if (callbackParameters == null || !callbackParameters.ContainsKey("code")) {
return false;
}
string authorizationResponse = PostAndReturn(new Uri(TokenUri), string.Format("grant_type=authorization_code&code={0}&client_id={1}&client_secret={2}", callbackParameters["code"], BoxCredentials.ClientId, BoxCredentials.ClientSecret));
var authorization = JsonSerializer.Deserialize<Authorization>(authorizationResponse);
Config.BoxToken = authorization.AccessToken;
IniConfig.Save();
return true;
}
/// <summary> /// <summary>
/// Download a url response as string /// Put string
/// </summary>
/// <param name="url">An Uri to specify the download location</param>
/// <param name="postMessage"></param>
/// <returns>string with the file content</returns>
public static string PostAndReturn(Uri url, string postMessage) {
HttpWebRequest webRequest = NetworkHelper.CreateWebRequest(url);
webRequest.Method = "POST";
webRequest.KeepAlive = true;
webRequest.Credentials = CredentialCache.DefaultCredentials;
webRequest.ContentType = "application/x-www-form-urlencoded";
byte[] data = Encoding.UTF8.GetBytes(postMessage);
using (var requestStream = webRequest.GetRequestStream()) {
requestStream.Write(data, 0, data.Length);
}
return NetworkHelper.GetResponse(webRequest);
}
/// <summary>
/// Upload parameters by post
/// </summary>
/// <param name="url"></param>
/// <param name="parameters"></param>
/// <returns>response</returns>
public static string HttpPost(string url, IDictionary<string, object> parameters) {
var webRequest = (HttpWebRequest)NetworkHelper.CreateWebRequest(url);
webRequest.Method = "POST";
webRequest.KeepAlive = true;
webRequest.Credentials = CredentialCache.DefaultCredentials;
webRequest.Headers.Add("Authorization", "Bearer " + Config.BoxToken);
NetworkHelper.WriteMultipartFormData(webRequest, parameters);
return NetworkHelper.GetResponse(webRequest);
}
/// <summary>
/// Upload file by PUT
/// </summary> /// </summary>
/// <param name="url"></param> /// <param name="url"></param>
/// <param name="content"></param> /// <param name="content"></param>
/// <param name="settings">OAuth2Settings</param>
/// <returns>response</returns> /// <returns>response</returns>
public static string HttpPut(string url, string content) { public static string HttpPut(string url, string content, OAuth2Settings settings) {
var webRequest = (HttpWebRequest)NetworkHelper.CreateWebRequest(url); var webRequest= OAuth2Helper.CreateOAuth2WebRequest(HTTPMethod.PUT, url, settings);
webRequest.Method = "PUT";
webRequest.KeepAlive = true;
webRequest.Credentials = CredentialCache.DefaultCredentials;
webRequest.Headers.Add("Authorization", "Bearer " + Config.BoxToken);
byte[] data = Encoding.UTF8.GetBytes(content); byte[] data = Encoding.UTF8.GetBytes(content);
using (var requestStream = webRequest.GetRequestStream()) { using (var requestStream = webRequest.GetRequestStream()) {
requestStream.Write(data, 0, data.Length); requestStream.Write(data, 0, data.Length);
} }
return NetworkHelper.GetResponse(webRequest); return NetworkHelper.GetResponseAsString(webRequest);
}
/// <summary>
/// Get REST request
/// </summary>
/// <param name="url"></param>
/// <returns>response</returns>
public static string HttpGet(string url) {
var webRequest = (HttpWebRequest)NetworkHelper.CreateWebRequest(url);
webRequest.Method = "GET";
webRequest.KeepAlive = true;
webRequest.Credentials = CredentialCache.DefaultCredentials;
webRequest.Headers.Add("Authorization", "Bearer " + Config.BoxToken);
return NetworkHelper.GetResponse(webRequest);
} }
/// <summary> /// <summary>
@ -143,45 +64,53 @@ namespace GreenshotBoxPlugin {
/// <param name="filename">Filename of box upload</param> /// <param name="filename">Filename of box upload</param>
/// <returns>url to uploaded image</returns> /// <returns>url to uploaded image</returns>
public static string UploadToBox(SurfaceContainer image, string title, string filename) { public static string UploadToBox(SurfaceContainer image, string title, string filename) {
while (true) {
const string folderId = "0";
if (string.IsNullOrEmpty(Config.BoxToken)) {
if (!Authorize()) {
return null;
}
}
IDictionary<string, object> parameters = new Dictionary<string, object>(); // Fill the OAuth2Settings
parameters.Add("filename", image); OAuth2Settings settings = new OAuth2Settings();
parameters.Add("parent_id", folderId);
settings.AuthUrlPattern = "https://www.box.com/api/oauth2/authorize?client_id={ClientId}&response_type={response_type}&state{State}&redirect_uri={RedirectUrl}";
settings.TokenUrlPattern = "https://www.box.com/api/oauth2/token";
settings.CloudServiceName = "Box";
settings.ClientId = BoxCredentials.ClientId;
settings.ClientSecret = BoxCredentials.ClientSecret;
settings.RedirectUrl = "https://www.box.com/home/";
settings.BrowserSize = new Size(1060, 600);
settings.AuthorizeMode = OAuth2AuthorizeMode.EmbeddedBrowser;
// Copy the settings from the config, which is kept in memory and on the disk
settings.RefreshToken = Config.RefreshToken;
settings.AccessToken = Config.AccessToken;
settings.AccessTokenExpires = Config.AccessTokenExpires;
var response = "";
try { try {
response = HttpPost(UploadFileUri, parameters); var webRequest = OAuth2Helper.CreateOAuth2WebRequest(HTTPMethod.POST, FilesUri, settings);
} catch (WebException ex) { IDictionary<string, object> parameters = new Dictionary<string, object>();
if (ex.Status == WebExceptionStatus.ProtocolError) { if (Config.AddFilename) {
Config.BoxToken = null; parameters.Add("filename", image);
continue;
}
} }
parameters.Add("parent_id", Config.FolderId);
NetworkHelper.WriteMultipartFormData(webRequest, parameters);
var response = NetworkHelper.GetResponseAsString(webRequest);
LOG.DebugFormat("Box response: {0}", response); LOG.DebugFormat("Box response: {0}", response);
// Check if the token is wrong
if ("wrong auth token".Equals(response)) {
Config.BoxToken = null;
IniConfig.Save();
continue;
}
var upload = JsonSerializer.Deserialize<Upload>(response); var upload = JsonSerializer.Deserialize<Upload>(response);
if (upload == null || upload.Entries == null || upload.Entries.Count == 0) return null; if (upload == null || upload.Entries == null || upload.Entries.Count == 0) return null;
if (Config.UseSharedLink) { if (Config.UseSharedLink) {
string filesResponse = HttpPut(string.Format(FilesUri, upload.Entries[0].Id), "{\"shared_link\": {\"access\": \"open\"}}"); string filesResponse = HttpPut(string.Format(FilesUri, upload.Entries[0].Id), "{\"shared_link\": {\"access\": \"open\"}}", settings);
var file = JsonSerializer.Deserialize<FileEntry>(filesResponse); var file = JsonSerializer.Deserialize<FileEntry>(filesResponse);
return file.SharedLink.Url; return file.SharedLink.Url;
} }
return string.Format("http://www.box.com/files/0/f/0/1/f_{0}", upload.Entries[0].Id); return string.Format("http://www.box.com/files/0/f/0/1/f_{0}", upload.Entries[0].Id);
} finally {
// Copy the settings back to the config, so they are stored.
Config.RefreshToken = settings.RefreshToken;
Config.AccessToken = settings.AccessToken;
Config.AccessTokenExpires = settings.AccessTokenExpires;
Config.IsDirty = true;
} }
} }
} }

View file

@ -122,8 +122,7 @@ namespace GreenshotImgurPlugin {
if (config.AnonymousAccess) { if (config.AnonymousAccess) {
// add key, we only use the other parameters for the AnonymousAccess // add key, we only use the other parameters for the AnonymousAccess
otherParameters.Add("key", IMGUR_ANONYMOUS_API_KEY); otherParameters.Add("key", IMGUR_ANONYMOUS_API_KEY);
HttpWebRequest webRequest = (HttpWebRequest)NetworkHelper.CreateWebRequest(config.ImgurApiUrl + "/upload.xml?" + NetworkHelper.GenerateQueryParameters(otherParameters)); HttpWebRequest webRequest = NetworkHelper.CreateWebRequest(config.ImgurApiUrl + "/upload.xml?" + NetworkHelper.GenerateQueryParameters(otherParameters), HTTPMethod.POST);
webRequest.Method = "POST";
webRequest.ContentType = "image/" + outputSettings.Format.ToString(); webRequest.ContentType = "image/" + outputSettings.Format.ToString();
webRequest.ServicePoint.Expect100Continue = false; webRequest.ServicePoint.Expect100Continue = false;
@ -194,8 +193,7 @@ namespace GreenshotImgurPlugin {
return; return;
} }
LOG.InfoFormat("Retrieving Imgur image for {0} with url {1}", imgurInfo.Hash, imgurInfo.SmallSquare); LOG.InfoFormat("Retrieving Imgur image for {0} with url {1}", imgurInfo.Hash, imgurInfo.SmallSquare);
HttpWebRequest webRequest = (HttpWebRequest)NetworkHelper.CreateWebRequest(imgurInfo.SmallSquare); HttpWebRequest webRequest = NetworkHelper.CreateWebRequest(imgurInfo.SmallSquare, HTTPMethod.GET);
webRequest.Method = "GET";
webRequest.ServicePoint.Expect100Continue = false; webRequest.ServicePoint.Expect100Continue = false;
SetClientId(webRequest); SetClientId(webRequest);
using (WebResponse response = webRequest.GetResponse()) { using (WebResponse response = webRequest.GetResponse()) {
@ -215,8 +213,7 @@ namespace GreenshotImgurPlugin {
public static ImgurInfo RetrieveImgurInfo(string hash, string deleteHash) { public static ImgurInfo RetrieveImgurInfo(string hash, string deleteHash) {
string url = config.ImgurApiUrl + "/image/" + hash; string url = config.ImgurApiUrl + "/image/" + hash;
LOG.InfoFormat("Retrieving Imgur info for {0} with url {1}", hash, url); LOG.InfoFormat("Retrieving Imgur info for {0} with url {1}", hash, url);
HttpWebRequest webRequest = (HttpWebRequest)NetworkHelper.CreateWebRequest(url); HttpWebRequest webRequest = NetworkHelper.CreateWebRequest(url, HTTPMethod.GET);
webRequest.Method = "GET";
webRequest.ServicePoint.Expect100Continue = false; webRequest.ServicePoint.Expect100Continue = false;
SetClientId(webRequest); SetClientId(webRequest);
string responseString; string responseString;
@ -250,10 +247,7 @@ namespace GreenshotImgurPlugin {
try { try {
string url = config.ImgurApiUrl + "/delete/" + imgurInfo.DeleteHash; string url = config.ImgurApiUrl + "/delete/" + imgurInfo.DeleteHash;
HttpWebRequest webRequest = (HttpWebRequest)NetworkHelper.CreateWebRequest(url); HttpWebRequest webRequest = NetworkHelper.CreateWebRequest(url, HTTPMethod.GET);
//webRequest.Method = "DELETE";
webRequest.Method = "GET";
webRequest.ServicePoint.Expect100Continue = false; webRequest.ServicePoint.Expect100Continue = false;
SetClientId(webRequest); SetClientId(webRequest);
string responseString; string responseString;

View file

@ -37,12 +37,6 @@ namespace GreenshotPicasaPlugin {
[IniProperty("AfterUploadLinkToClipBoard", Description = "After upload send Picasa link to clipboard.", DefaultValue = "true")] [IniProperty("AfterUploadLinkToClipBoard", Description = "After upload send Picasa link to clipboard.", DefaultValue = "true")]
public bool AfterUploadLinkToClipBoard; public bool AfterUploadLinkToClipBoard;
[IniProperty("RefreshToken", Description = "Picasa refresh Token", Encrypted = true)]
public string RefreshToken {
get;
set;
}
[IniProperty("AddFilename", Description = "Is the filename passed on to Picasa", DefaultValue = "False")] [IniProperty("AddFilename", Description = "Is the filename passed on to Picasa", DefaultValue = "False")]
public bool AddFilename { public bool AddFilename {
get; get;
@ -61,6 +55,12 @@ namespace GreenshotPicasaPlugin {
set; set;
} }
[IniProperty("RefreshToken", Description = "Picasa authorization refresh Token", Encrypted = true)]
public string RefreshToken {
get;
set;
}
/// <summary> /// <summary>
/// Not stored /// Not stored
/// </summary> /// </summary>

View file

@ -50,10 +50,12 @@ namespace GreenshotPicasaPlugin {
OAuth2Settings settings = new OAuth2Settings(); OAuth2Settings settings = new OAuth2Settings();
settings.AuthUrlPattern = AuthUrl; settings.AuthUrlPattern = AuthUrl;
settings.TokenUrlPattern = TokenUrl; settings.TokenUrlPattern = TokenUrl;
settings.CloudServiceName = "Picasa";
settings.AdditionalAttributes.Add("response_type", "code"); settings.AdditionalAttributes.Add("response_type", "code");
settings.AdditionalAttributes.Add("scope", PicasaScope); settings.AdditionalAttributes.Add("scope", PicasaScope);
settings.ClientId = PicasaCredentials.ClientId; settings.ClientId = PicasaCredentials.ClientId;
settings.ClientSecret = PicasaCredentials.ClientSecret; settings.ClientSecret = PicasaCredentials.ClientSecret;
settings.AuthorizeMode = OAuth2AuthorizeMode.LocalServer;
// Copy the settings from the config, which is kept in memory and on the disk // Copy the settings from the config, which is kept in memory and on the disk
settings.RefreshToken = Config.RefreshToken; settings.RefreshToken = Config.RefreshToken;
@ -61,27 +63,14 @@ namespace GreenshotPicasaPlugin {
settings.AccessTokenExpires = Config.AccessTokenExpires; settings.AccessTokenExpires = Config.AccessTokenExpires;
try { try {
// Get Refresh / Access token var webRequest = OAuth2Helper.CreateOAuth2WebRequest(HTTPMethod.POST, string.Format(UploadUrl, Config.UploadUser, Config.UploadAlbum), settings);
if (string.IsNullOrEmpty(settings.RefreshToken)) {
OAuth2Helper.AuthenticateViaLocalServer(settings);
}
if (settings.IsAccessTokenExpired) {
OAuth2Helper.GenerateAccessToken(settings);
}
var webRequest = (HttpWebRequest)NetworkHelper.CreateWebRequest(string.Format(UploadUrl, Config.UploadUser, Config.UploadAlbum));
webRequest.Method = "POST";
webRequest.KeepAlive = true;
webRequest.Credentials = CredentialCache.DefaultCredentials;
OAuth2Helper.AddOAuth2Credentials(webRequest, settings);
if (Config.AddFilename) { if (Config.AddFilename) {
webRequest.Headers.Add("Slug", NetworkHelper.EscapeDataString(filename)); webRequest.Headers.Add("Slug", NetworkHelper.EscapeDataString(filename));
} }
SurfaceContainer container = new SurfaceContainer(surfaceToUpload, outputSettings, filename); SurfaceContainer container = new SurfaceContainer(surfaceToUpload, outputSettings, filename);
container.Upload(webRequest); container.Upload(webRequest);
string response = NetworkHelper.GetResponse(webRequest); string response = NetworkHelper.GetResponseAsString(webRequest);
return ParseResponse(response); return ParseResponse(response);
} finally { } finally {
@ -89,6 +78,7 @@ namespace GreenshotPicasaPlugin {
Config.RefreshToken = settings.RefreshToken; Config.RefreshToken = settings.RefreshToken;
Config.AccessToken = settings.AccessToken; Config.AccessToken = settings.AccessToken;
Config.AccessTokenExpires = settings.AccessTokenExpires; Config.AccessTokenExpires = settings.AccessTokenExpires;
Config.IsDirty = true;
} }
} }

View file

@ -87,7 +87,7 @@ namespace GreenshotPlugin.Controls {
/// <summary> /// <summary>
/// When this is set, the form will be brought to the foreground as soon as it is shown. /// When this is set, the form will be brought to the foreground as soon as it is shown.
/// </summary> /// </summary>
protected bool BringToFront { protected bool ToFront {
get; get;
set; set;
} }
@ -162,7 +162,7 @@ namespace GreenshotPlugin.Controls {
/// <param name="e">EventArgs</param> /// <param name="e">EventArgs</param>
protected override void OnShown(EventArgs e) { protected override void OnShown(EventArgs e) {
base.OnShown(e); base.OnShown(e);
if (BringToFront) { if (ToFront) {
WindowDetails.ToForeground(Handle); WindowDetails.ToForeground(Handle);
} }
} }

View file

@ -44,37 +44,37 @@ namespace GreenshotPlugin.Controls {
/// the contents of this method with the code editor. /// the contents of this method with the code editor.
/// </summary> /// </summary>
private void InitializeComponent() { private void InitializeComponent() {
this.addressTextBox = new System.Windows.Forms.TextBox(); this._addressTextBox = new System.Windows.Forms.TextBox();
this.browser = new ExtendedWebBrowser(); this._browser = new ExtendedWebBrowser();
this.SuspendLayout(); this.SuspendLayout();
// //
// addressTextBox // _addressTextBox
// //
this.addressTextBox.Cursor = System.Windows.Forms.Cursors.Arrow; this._addressTextBox.Cursor = System.Windows.Forms.Cursors.Arrow;
this.addressTextBox.Dock = System.Windows.Forms.DockStyle.Top; this._addressTextBox.Dock = System.Windows.Forms.DockStyle.Top;
this.addressTextBox.Enabled = false; this._addressTextBox.Enabled = false;
this.addressTextBox.Location = new System.Drawing.Point(0, 0); this._addressTextBox.Location = new System.Drawing.Point(0, 0);
this.addressTextBox.Name = "addressTextBox"; this._addressTextBox.Name = "addressTextBox";
this.addressTextBox.Size = new System.Drawing.Size(595, 20); this._addressTextBox.Size = new System.Drawing.Size(595, 20);
this.addressTextBox.TabIndex = 3; this._addressTextBox.TabIndex = 3;
this.addressTextBox.TabStop = false; this._addressTextBox.TabStop = false;
// //
// browser // _browser
// //
this.browser.Dock = System.Windows.Forms.DockStyle.Fill; this._browser.Dock = System.Windows.Forms.DockStyle.Fill;
this.browser.Location = new System.Drawing.Point(0, 20); this._browser.Location = new System.Drawing.Point(0, 20);
this.browser.MinimumSize = new System.Drawing.Size(100, 100); this._browser.MinimumSize = new System.Drawing.Size(100, 100);
this.browser.Name = "browser"; this._browser.Name = "browser";
this.browser.Size = new System.Drawing.Size(595, 295); this._browser.Size = new System.Drawing.Size(595, 295);
this.browser.TabIndex = 4; this._browser.TabIndex = 4;
// //
// OAuthLoginForm // OAuthLoginForm
// //
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(595, 315); this.ClientSize = new System.Drawing.Size(595, 315);
this.Controls.Add(this.browser); this.Controls.Add(this._browser);
this.Controls.Add(this.addressTextBox); this.Controls.Add(this._addressTextBox);
this.MaximizeBox = false; this.MaximizeBox = false;
this.MinimizeBox = false; this.MinimizeBox = false;
this.Name = "OAuthLoginForm"; this.Name = "OAuthLoginForm";
@ -85,8 +85,8 @@ namespace GreenshotPlugin.Controls {
#endregion #endregion
private System.Windows.Forms.TextBox addressTextBox; private System.Windows.Forms.TextBox _addressTextBox;
private ExtendedWebBrowser browser; private ExtendedWebBrowser _browser;
} }
} }

View file

@ -35,31 +35,33 @@ namespace GreenshotPlugin.Controls {
/// </summary> /// </summary>
public partial class OAuthLoginForm : Form { public partial class OAuthLoginForm : Form {
private static readonly ILog LOG = LogManager.GetLogger(typeof(OAuthLoginForm)); private static readonly ILog LOG = LogManager.GetLogger(typeof(OAuthLoginForm));
private string callbackUrl = null; private string _callbackUrl = null;
private IDictionary<string, string> callbackParameters = null; private IDictionary<string, string> _callbackParameters = null;
public IDictionary<string, string> CallbackParameters { public IDictionary<string, string> CallbackParameters {
get { return callbackParameters; } get {
return _callbackParameters;
}
} }
public bool isOk { public bool IsOk {
get { get {
return DialogResult == DialogResult.OK; return DialogResult == DialogResult.OK;
} }
} }
public OAuthLoginForm(string browserTitle, Size size, string authorizationLink, string callbackUrl) { public OAuthLoginForm(string browserTitle, Size size, string authorizationLink, string callbackUrl) {
this.callbackUrl = callbackUrl; _callbackUrl = callbackUrl;
InitializeComponent(); InitializeComponent();
ClientSize = size; ClientSize = size;
Icon = GreenshotResources.getGreenshotIcon(); Icon = GreenshotResources.getGreenshotIcon();
Text = browserTitle; Text = browserTitle;
addressTextBox.Text = authorizationLink; _addressTextBox.Text = authorizationLink;
// The script errors are suppressed by using the ExtendedWebBrowser // The script errors are suppressed by using the ExtendedWebBrowser
browser.ScriptErrorsSuppressed = false; _browser.ScriptErrorsSuppressed = false;
browser.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(browser_DocumentCompleted); _browser.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(Browser_DocumentCompleted);
browser.Navigate(new Uri(authorizationLink)); _browser.Navigate(new Uri(authorizationLink));
} }
/// <summary> /// <summary>
@ -71,33 +73,24 @@ namespace GreenshotPlugin.Controls {
WindowDetails.ToForeground(Handle); WindowDetails.ToForeground(Handle);
} }
private void browser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) { private void Browser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) {
LOG.DebugFormat("document completed with url: {0}", browser.Url); LOG.DebugFormat("document completed with url: {0}", _browser.Url);
checkUrl(); CheckUrl();
}
private void webBrowser1_Navigating(object sender, WebBrowserNavigatingEventArgs e) {
LOG.DebugFormat("Navigating to url: {0}", browser.Url);
addressTextBox.Text = e.Url.ToString();
} }
private void browser_Navigated(object sender, WebBrowserNavigatedEventArgs e) { private void CheckUrl() {
LOG.DebugFormat("Navigated to url: {0}", browser.Url); if (_browser.Url.ToString().StartsWith(_callbackUrl)) {
checkUrl(); string queryParams = _browser.Url.Query;
}
private void checkUrl() {
if (browser.Url.ToString().StartsWith(callbackUrl)) {
string queryParams = browser.Url.Query;
if (queryParams.Length > 0) { if (queryParams.Length > 0) {
queryParams = NetworkHelper.UrlDecode(queryParams); queryParams = NetworkHelper.UrlDecode(queryParams);
//Store the Token and Token Secret //Store the Token and Token Secret
callbackParameters = NetworkHelper.ParseQueryString(queryParams); _callbackParameters = NetworkHelper.ParseQueryString(queryParams);
} }
DialogResult = DialogResult.OK; DialogResult = DialogResult.OK;
} }
} }
private void addressTextBox_KeyPress(object sender, KeyPressEventArgs e) { private void AddressTextBox_KeyPress(object sender, KeyPressEventArgs e) {
//Cancel the key press so the user can't enter a new url //Cancel the key press so the user can't enter a new url
e.Handled = true; e.Handled = true;
} }

View file

@ -47,7 +47,7 @@ namespace GreenshotPlugin.Controls {
trackBarJpegQuality.Value = Settings.JPGQuality; trackBarJpegQuality.Value = Settings.JPGQuality;
textBoxJpegQuality.Enabled = OutputFormat.jpg.Equals(outputSettings.Format); textBoxJpegQuality.Enabled = OutputFormat.jpg.Equals(outputSettings.Format);
textBoxJpegQuality.Text = Settings.JPGQuality.ToString(); textBoxJpegQuality.Text = Settings.JPGQuality.ToString();
BringToFront = true; ToFront = true;
} }
void Button_okClick(object sender, EventArgs e) { void Button_okClick(object sender, EventArgs e) {

View file

@ -33,6 +33,17 @@ using System.Text;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
namespace GreenshotPlugin.Core { namespace GreenshotPlugin.Core {
/// <summary>
/// HTTP Method to make sure we have the correct method
/// </summary>
public enum HTTPMethod {
GET,
POST,
PUT,
DELETE,
HEAD
};
/// <summary> /// <summary>
/// Description of NetworkHelper. /// Description of NetworkHelper.
/// </summary> /// </summary>
@ -55,10 +66,7 @@ namespace GreenshotPlugin.Core {
/// <returns>string with the file content</returns> /// <returns>string with the file content</returns>
public static string GetAsString(Uri uri) { public static string GetAsString(Uri uri) {
HttpWebRequest webRequest = CreateWebRequest(uri); HttpWebRequest webRequest = CreateWebRequest(uri);
webRequest.Method = "GET"; return GetResponseAsString(CreateWebRequest(uri));
webRequest.KeepAlive = true;
webRequest.Credentials = CredentialCache.DefaultCredentials;
return GetResponse(webRequest);
} }
/// <summary> /// <summary>
@ -143,7 +151,7 @@ namespace GreenshotPlugin.Core {
} }
/// <summary> /// <summary>
/// Helper method to create a web request, eventually with proxy /// Helper method to create a web request with a lot of default settings
/// </summary> /// </summary>
/// <param name="uri">string with uri to connect to</param> /// <param name="uri">string with uri to connect to</param>
/// <returns>WebRequest</returns> /// <returns>WebRequest</returns>
@ -151,6 +159,28 @@ namespace GreenshotPlugin.Core {
return CreateWebRequest(new Uri(uri)); return CreateWebRequest(new Uri(uri));
} }
/// <summary>
/// Helper method to create a web request with a lot of default settings
/// </summary>
/// <param name="uri">string with uri to connect to</param>
/// /// <param name="method">Method to use</param>
/// <returns>WebRequest</returns>
public static HttpWebRequest CreateWebRequest(string uri, HTTPMethod method) {
return CreateWebRequest(new Uri(uri), method);
}
/// <summary>
/// Helper method to create a web request with a lot of default settings
/// </summary>
/// <param name="uri">Uri with uri to connect to</param>
/// <param name="method">Method to use</param>
/// <returns>WebRequest</returns>
public static HttpWebRequest CreateWebRequest(Uri uri, HTTPMethod method) {
HttpWebRequest webRequest = CreateWebRequest(uri);
webRequest.Method = method.ToString();
return webRequest;
}
/// <summary> /// <summary>
/// Helper method to create a web request, eventually with proxy /// Helper method to create a web request, eventually with proxy
/// </summary> /// </summary>
@ -164,6 +194,10 @@ namespace GreenshotPlugin.Core {
// BUG-1655: Fix that Greenshot always uses the default proxy even if the "use default proxy" checkbox is unset // BUG-1655: Fix that Greenshot always uses the default proxy even if the "use default proxy" checkbox is unset
webRequest.Proxy = null; webRequest.Proxy = null;
} }
// Make sure the default credentials are available
webRequest.Credentials = CredentialCache.DefaultCredentials;
// Allow redirect, this is usually needed so that we don't get a problem when a service moves
webRequest.AllowAutoRedirect = true; webRequest.AllowAutoRedirect = true;
// Set default timeouts // Set default timeouts
webRequest.Timeout = Config.WebRequestTimeout*1000; webRequest.Timeout = Config.WebRequestTimeout*1000;
@ -365,7 +399,7 @@ namespace GreenshotPlugin.Core {
using (var streamWriter = new StreamWriter(requestStream, Encoding.UTF8)) { using (var streamWriter = new StreamWriter(requestStream, Encoding.UTF8)) {
streamWriter.Write(urlEncoded); streamWriter.Write(urlEncoded);
} }
return GetResponse(webRequest); return GetResponseAsString(webRequest);
} }
/// <summary> /// <summary>
@ -388,7 +422,7 @@ namespace GreenshotPlugin.Core {
/// <param name="webRequest">The request object.</param> /// <param name="webRequest">The request object.</param>
/// <returns>The response data.</returns> /// <returns>The response data.</returns>
/// TODO: This method should handle the StatusCode better! /// TODO: This method should handle the StatusCode better!
public static string GetResponse(HttpWebRequest webRequest) { public static string GetResponseAsString(HttpWebRequest webRequest) {
string responseData = null; string responseData = null;
try { try {
HttpWebResponse response = (HttpWebResponse) webRequest.GetResponse(); HttpWebResponse response = (HttpWebResponse) webRequest.GetResponse();
@ -429,7 +463,7 @@ namespace GreenshotPlugin.Core {
public static DateTime GetLastModified(Uri uri) { public static DateTime GetLastModified(Uri uri) {
try { try {
HttpWebRequest webRequest = CreateWebRequest(uri); HttpWebRequest webRequest = CreateWebRequest(uri);
webRequest.Method = "HEAD"; webRequest.Method = HTTPMethod.HEAD.ToString();
HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse(); HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse();
LOG.DebugFormat("RSS feed was updated at {0}", webResponse.LastModified); LOG.DebugFormat("RSS feed was updated at {0}", webResponse.LastModified);
return webResponse.LastModified; return webResponse.LastModified;

View file

@ -46,9 +46,15 @@ namespace GreenshotPlugin.Core {
} }
/// <summary> /// <summary>
/// Used HTTP Method, this is for the OAuth 1.x protocol /// Specify the autorize mode that is used to get the token from the cloud service.
/// </summary> /// </summary>
public enum HTTPMethod { GET, POST, PUT, DELETE }; public enum OAuth2AuthorizeMode {
Unknown, // Will give an exception, caller needs to specify another value
LocalServer, // Will specify a redirect URL to http://localhost:port/authorize, while having a HttpListener
MonitorTitle, // Not implemented yet: Will monitor for title changes
Pin, // Not implemented yet: Will ask the user to enter the shown PIN
EmbeddedBrowser // Will open into an embedded _browser (OAuthLoginForm), and catch the redirect
}
/// <summary> /// <summary>
/// Settings for the OAuth 2 protocol /// Settings for the OAuth 2 protocol
@ -58,6 +64,28 @@ namespace GreenshotPlugin.Core {
AdditionalAttributes = new Dictionary<string, string>(); AdditionalAttributes = new Dictionary<string, string>();
// Create a default state // Create a default state
State = Guid.NewGuid().ToString(); State = Guid.NewGuid().ToString();
AuthorizeMode = OAuth2AuthorizeMode.Unknown;
}
public OAuth2AuthorizeMode AuthorizeMode {
get;
set;
}
/// <summary>
/// Specify the name of the cloud service, so it can be used in window titles, logs etc
/// </summary>
public string CloudServiceName {
get;
set;
}
/// <summary>
/// Specify the size of the embedded Browser, if using this
/// </summary>
public Size BrowserSize {
get;
set;
} }
/// <summary> /// <summary>
@ -242,7 +270,7 @@ namespace GreenshotPlugin.Core {
private readonly string _consumerKey; private readonly string _consumerKey;
private readonly string _consumerSecret; private readonly string _consumerSecret;
// default browser size // default _browser size
private Size _browserSize = new Size(864, 587); private Size _browserSize = new Size(864, 587);
private string _loginTitle = "Authorize Greenshot access"; private string _loginTitle = "Authorize Greenshot access";
@ -479,7 +507,7 @@ namespace GreenshotPlugin.Core {
LOG.DebugFormat("Opening AuthorizationLink: {0}", AuthorizationLink); LOG.DebugFormat("Opening AuthorizationLink: {0}", AuthorizationLink);
OAuthLoginForm oAuthLoginForm = new OAuthLoginForm(LoginTitle, BrowserSize, AuthorizationLink, CallbackUrl); OAuthLoginForm oAuthLoginForm = new OAuthLoginForm(LoginTitle, BrowserSize, AuthorizationLink, CallbackUrl);
oAuthLoginForm.ShowDialog(); oAuthLoginForm.ShowDialog();
if (oAuthLoginForm.isOk) { if (oAuthLoginForm.IsOk) {
if (oAuthLoginForm.CallbackParameters != null) { if (oAuthLoginForm.CallbackParameters != null) {
string tokenValue; string tokenValue;
if (oAuthLoginForm.CallbackParameters.TryGetValue(OAUTH_TOKEN_KEY, out tokenValue)) { if (oAuthLoginForm.CallbackParameters.TryGetValue(OAUTH_TOKEN_KEY, out tokenValue)) {
@ -812,11 +840,9 @@ namespace GreenshotPlugin.Core {
} }
} }
// Create webrequest // Create webrequest
HttpWebRequest webRequest = NetworkHelper.CreateWebRequest(requestURL); HttpWebRequest webRequest = NetworkHelper.CreateWebRequest(requestURL, method);
webRequest.Method = method.ToString();
webRequest.ServicePoint.Expect100Continue = false; webRequest.ServicePoint.Expect100Continue = false;
webRequest.UserAgent = _userAgent; webRequest.UserAgent = _userAgent;
webRequest.Timeout = 100000;
if (UseHTTPHeadersForAuthorization && authHeader != null) { if (UseHTTPHeadersForAuthorization && authHeader != null) {
LOG.DebugFormat("Authorization: OAuth {0}", authHeader); LOG.DebugFormat("Authorization: OAuth {0}", authHeader);
@ -860,7 +886,7 @@ namespace GreenshotPlugin.Core {
string responseData; string responseData;
try { try {
responseData = NetworkHelper.GetResponse(webRequest); responseData = NetworkHelper.GetResponseAsString(webRequest);
LOG.DebugFormat("Response: {0}", responseData); LOG.DebugFormat("Response: {0}", responseData);
} catch (Exception ex) { } catch (Exception ex) {
LOG.Error("Couldn't retrieve response: ", ex); LOG.Error("Couldn't retrieve response: ", ex);
@ -879,6 +905,7 @@ namespace GreenshotPlugin.Core {
/// </summary> /// </summary>
public class LocalServerCodeReceiver { public class LocalServerCodeReceiver {
private static readonly ILog LOG = LogManager.GetLogger(typeof(LocalServerCodeReceiver)); private static readonly ILog LOG = LogManager.GetLogger(typeof(LocalServerCodeReceiver));
private readonly ManualResetEvent _ready = new ManualResetEvent(true);
private string _loopbackCallback = "http://localhost:{0}/authorize/"; private string _loopbackCallback = "http://localhost:{0}/authorize/";
/// <summary> /// <summary>
@ -896,9 +923,9 @@ namespace GreenshotPlugin.Core {
private string _closePageResponse = private string _closePageResponse =
@"<html> @"<html>
<head><title>OAuth 2.0 Authentication Token Received</title></head> <head><title>OAuth 2.0 Authentication CloudServiceName</title></head>
<body> <body>
Greenshot received verification code. You can close this browser / tab if it is not closed itself... Greenshot received information from CloudServiceName. You can close this browser / tab if it is not closed itself...
<script type='text/javascript'> <script type='text/javascript'>
window.setTimeout(function() { window.setTimeout(function() {
window.open('', '_self', ''); window.open('', '_self', '');
@ -912,7 +939,8 @@ Greenshot received verification code. You can close this browser / tab if it is
</html>"; </html>";
/// <summary> /// <summary>
/// HTML code to to return the browser, default it will try to close the browser / tab, this won't always work. /// HTML code to to return the _browser, default it will try to close the _browser / tab, this won't always work.
/// You can use CloudServiceName where you want to show the CloudServiceName from your OAuth2 settings
/// </summary> /// </summary>
public string ClosePageResponse { public string ClosePageResponse {
get { get {
@ -937,6 +965,11 @@ Greenshot received verification code. You can close this browser / tab if it is
} }
} }
private string _cloudServiceName;
private IDictionary<string, string> _returnValues = new Dictionary<string, string>();
/// <summary> /// <summary>
/// The OAuth code receiver /// The OAuth code receiver
/// </summary> /// </summary>
@ -945,6 +978,7 @@ Greenshot received verification code. You can close this browser / tab if it is
public IDictionary<string, string> ReceiveCode(OAuth2Settings oauth2Settings) { public IDictionary<string, string> ReceiveCode(OAuth2Settings oauth2Settings) {
// Set the redirect URL on the settings // Set the redirect URL on the settings
oauth2Settings.RedirectUrl = RedirectUri; oauth2Settings.RedirectUrl = RedirectUri;
_cloudServiceName = oauth2Settings.CloudServiceName;
using (var listener = new HttpListener()) { using (var listener = new HttpListener()) {
listener.Prefixes.Add(oauth2Settings.RedirectUrl); listener.Prefixes.Add(oauth2Settings.RedirectUrl);
try { try {
@ -956,31 +990,67 @@ Greenshot received verification code. You can close this browser / tab if it is
Process.Start(authorizationUrl); Process.Start(authorizationUrl);
// Wait to get the authorization code response. // Wait to get the authorization code response.
var context = listener.GetContext(); var context = listener.BeginGetContext(new AsyncCallback(ListenerCallback), listener);
try { _ready.Reset();
NameValueCollection nameValueCollection = context.Request.QueryString;
// Write a "close" response. while (!context.AsyncWaitHandle.WaitOne(1000, true)) {
using (var writer = new StreamWriter(context.Response.OutputStream)) { LOG.Debug("Waiting for response");
writer.WriteLine(ClosePageResponse);
writer.Flush();
}
// Create a new response URL with a dictionary that contains all the response query parameters.
IDictionary<string, string> returnValues = new Dictionary<string, string>();
foreach (var name in nameValueCollection.AllKeys) {
if (!returnValues.ContainsKey(name)) {
returnValues.Add(name, nameValueCollection[name]);
}
}
return returnValues;
} finally {
context.Response.OutputStream.Close();
} }
} catch (Exception) {
// Make sure we can clean up, also if the thead is aborted
_ready.Set();
throw;
} finally { } finally {
_ready.WaitOne();
listener.Close(); listener.Close();
} }
} }
return _returnValues;
}
/// <summary>
/// Handle a connection async, this allows us to break the waiting
/// </summary>
/// <param name="result">IAsyncResult</param>
private void ListenerCallback(IAsyncResult result) {
HttpListener listener = (HttpListener)result.AsyncState;
//If not listening return immediately as this method is called one last time after Close()
if (!listener.IsListening) {
return;
}
// Use EndGetContext to complete the asynchronous operation.
HttpListenerContext context = listener.EndGetContext(result);
// Handle request
HttpListenerRequest request = context.Request;
try {
NameValueCollection nameValueCollection = request.QueryString;
// Get response object.
using (HttpListenerResponse response = context.Response) {
// Write a "close" response.
byte[] buffer = System.Text.Encoding.UTF8.GetBytes(ClosePageResponse.Replace("CloudServiceName", _cloudServiceName));
// Write to response stream.
response.ContentLength64 = buffer.Length;
using (var stream = response.OutputStream) {
stream.Write(buffer, 0, buffer.Length);
}
}
// Create a new response URL with a dictionary that contains all the response query parameters.
foreach (var name in nameValueCollection.AllKeys) {
if (!_returnValues.ContainsKey(name)) {
_returnValues.Add(name, nameValueCollection[name]);
}
}
} catch (Exception ex) {
context.Response.OutputStream.Close();
throw;
}
_ready.Set();
} }
/// <summary> /// <summary>
@ -1002,23 +1072,6 @@ Greenshot received verification code. You can close this browser / tab if it is
/// Code to simplify OAuth 2 /// Code to simplify OAuth 2
/// </summary> /// </summary>
public static class OAuth2Helper { public static class OAuth2Helper {
/// <summary>
/// Upload parameters by post
/// </summary>
/// <param name="url"></param>
/// <param name="parameters">Form-Url-Parameters</param>
/// <param name="settings">OAuth2Settings</param>
/// <returns>response</returns>
public static string HttpPost(string url, IDictionary<string, object> parameters, OAuth2Settings settings) {
HttpWebRequest webRequest = (HttpWebRequest)NetworkHelper.CreateWebRequest(url);
webRequest.Method = "POST";
webRequest.KeepAlive = true;
webRequest.Credentials = CredentialCache.DefaultCredentials;
AddOAuth2Credentials(webRequest, settings);
return NetworkHelper.UploadFormUrlEncoded(webRequest, parameters);
}
/// <summary> /// <summary>
/// Generate an OAuth 2 Token by using the supplied code /// Generate an OAuth 2 Token by using the supplied code
/// </summary> /// </summary>
@ -1033,7 +1086,8 @@ Greenshot received verification code. You can close this browser / tab if it is
data.Add("client_secret", settings.ClientSecret); data.Add("client_secret", settings.ClientSecret);
data.Add("grant_type", "authorization_code"); data.Add("grant_type", "authorization_code");
string accessTokenJsonResult = HttpPost(settings.FormattedTokenUrl, data, settings); HttpWebRequest webRequest = NetworkHelper.CreateWebRequest(settings.FormattedTokenUrl, HTTPMethod.POST);
string accessTokenJsonResult = NetworkHelper.UploadFormUrlEncoded(webRequest, data);
IDictionary<string, object> refreshTokenResult = JSONHelper.JsonDecode(accessTokenJsonResult); IDictionary<string, object> refreshTokenResult = JSONHelper.JsonDecode(accessTokenJsonResult);
// gives as described here: https://developers.google.com/identity/protocols/OAuth2InstalledApp // gives as described here: https://developers.google.com/identity/protocols/OAuth2InstalledApp
// "access_token":"1/fFAGRNJru1FTz70BzhT3Zg", // "access_token":"1/fFAGRNJru1FTz70BzhT3Zg",
@ -1061,7 +1115,9 @@ Greenshot received verification code. You can close this browser / tab if it is
data.Add("client_secret", settings.ClientSecret); data.Add("client_secret", settings.ClientSecret);
data.Add("grant_type", "refresh_token"); data.Add("grant_type", "refresh_token");
string accessTokenJsonResult = HttpPost(settings.FormattedTokenUrl, data, settings); HttpWebRequest webRequest = NetworkHelper.CreateWebRequest(settings.FormattedTokenUrl, HTTPMethod.POST);
string accessTokenJsonResult = NetworkHelper.UploadFormUrlEncoded(webRequest, data);
// gives as described here: https://developers.google.com/identity/protocols/OAuth2InstalledApp // gives as described here: https://developers.google.com/identity/protocols/OAuth2InstalledApp
// "access_token":"1/fFAGRNJru1FTz70BzhT3Zg", // "access_token":"1/fFAGRNJru1FTz70BzhT3Zg",
// "expires_in":3920, // "expires_in":3920,
@ -1076,26 +1132,78 @@ Greenshot received verification code. You can close this browser / tab if it is
} }
/// <summary> /// <summary>
/// Authenticate via a local server by using the LocalServerCodeReceiver /// Authenticate by using the mode specified in the settings
/// If this works, immediately generate a refresh token afterwards, otherwise this throws an exception /// </summary>
/// <param name="settings">OAuth2Settings</param>
/// <returns>false if it was canceled, true if it worked, exception if not</returns>
public static bool Authenticate(OAuth2Settings settings) {
bool completed = true;
switch (settings.AuthorizeMode) {
case OAuth2AuthorizeMode.LocalServer:
completed = AuthenticateViaLocalServer(settings);
break;
case OAuth2AuthorizeMode.EmbeddedBrowser:
completed = AuthenticateViaEmbeddedBrowser(settings);
break;
default:
throw new NotImplementedException(string.Format("Authorize mode '{0}' is not 'yet' implemented.", settings.AuthorizeMode));
}
return completed;
}
/// <summary>
/// Authenticate via an embedded browser
/// If this works, return the code
/// </summary> /// </summary>
/// <param name="settings">OAuth2Settings with the Auth / Token url etc</param> /// <param name="settings">OAuth2Settings with the Auth / Token url etc</param>
public static void AuthenticateViaLocalServer(OAuth2Settings settings) { /// <returns>true if completed, false if canceled</returns>
private static bool AuthenticateViaEmbeddedBrowser(OAuth2Settings settings) {
if (string.IsNullOrEmpty(settings.CloudServiceName)) {
throw new ArgumentNullException("CloudServiceName");
}
if (settings.BrowserSize == Size.Empty) {
throw new ArgumentNullException("BrowserSize");
}
OAuthLoginForm loginForm = new OAuthLoginForm(string.Format("Authorize {0}", settings.CloudServiceName), settings.BrowserSize, settings.FormattedAuthUrl, settings.RedirectUrl);
loginForm.ShowDialog();
if (loginForm.IsOk) {
string code;
if (loginForm.CallbackParameters.TryGetValue("code", out code) && !string.IsNullOrEmpty(code)) {
GenerateRefreshToken(code, settings);
return true;
}
}
return false;
}
/// <summary>
/// Authenticate via a local server by using the LocalServerCodeReceiver
/// If this works, return the code
/// </summary>
/// <param name="settings">OAuth2Settings with the Auth / Token url etc</param>
/// <returns>true if completed</returns>
private static bool AuthenticateViaLocalServer(OAuth2Settings settings) {
var codeReceiver = new LocalServerCodeReceiver(); var codeReceiver = new LocalServerCodeReceiver();
IDictionary<string, string> result = codeReceiver.ReceiveCode(settings); IDictionary<string, string> result = codeReceiver.ReceiveCode(settings);
string code; string code;
if (result.TryGetValue("code", out code)) { if (result.TryGetValue("code", out code) && !string.IsNullOrEmpty(code)) {
GenerateRefreshToken(code, settings); GenerateRefreshToken(code, settings);
return true;
} }
string error; string error;
if (result.TryGetValue("error", out error)) { if (result.TryGetValue("error", out error)) {
string errorDescription;
if (result.TryGetValue("error_description", out errorDescription)) {
throw new Exception(errorDescription);
}
if ("access_denied" == error) { if ("access_denied" == error) {
throw new UnauthorizedAccessException("Access denied"); throw new UnauthorizedAccessException("Access denied");
} else { } else {
throw new Exception(error); throw new Exception(error);
} }
} }
return false;
} }
/// <summary> /// <summary>
@ -1108,5 +1216,38 @@ Greenshot received verification code. You can close this browser / tab if it is
webRequest.Headers.Add("Authorization", "Bearer " + settings.AccessToken); webRequest.Headers.Add("Authorization", "Bearer " + settings.AccessToken);
} }
} }
/// <summary>
/// Check and authenticate or refresh tokens
/// </summary>
/// <param name="settings">OAuth2Settings</param>
public static void CheckAndAuthenticateOrRefresh(OAuth2Settings settings) {
// Get Refresh / Access token
if (string.IsNullOrEmpty(settings.RefreshToken)) {
if (!OAuth2Helper.Authenticate(settings)) {
throw new Exception("Authentication cancelled");
}
}
if (settings.IsAccessTokenExpired) {
OAuth2Helper.GenerateAccessToken(settings);
}
}
/// <summary>
/// CreateWebRequest ready for OAuth 2 access
/// </summary>
/// <param name="method">HTTPMethod</param>
/// <param name="url"></param>
/// <param name="settings">OAuth2Settings</param>
/// <returns>HttpWebRequest</returns>
public static HttpWebRequest CreateOAuth2WebRequest(HTTPMethod method, string url, OAuth2Settings settings) {
CheckAndAuthenticateOrRefresh(settings);
HttpWebRequest webRequest = (HttpWebRequest)NetworkHelper.CreateWebRequest(url, method);
OAuth2Helper.AddOAuth2Credentials(webRequest, settings);
return webRequest;
}
} }
} }

View file

@ -18,6 +18,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
@ -113,10 +114,9 @@ namespace GreenshotPlugin.Core {
/// </summary> /// </summary>
/// <returns>Dictionary<string, Dictionary<string, RssFile>> with files and their RssFile "description"</returns> /// <returns>Dictionary<string, Dictionary<string, RssFile>> with files and their RssFile "description"</returns>
public static Dictionary<string, Dictionary<string, SourceforgeFile>> readRSS() { public static Dictionary<string, Dictionary<string, SourceforgeFile>> readRSS() {
HttpWebRequest webRequest;
XmlDocument rssDoc = new XmlDocument(); XmlDocument rssDoc = new XmlDocument();
try { try {
webRequest = (HttpWebRequest)NetworkHelper.CreateWebRequest(RSSFEED); HttpWebRequest webRequest = NetworkHelper.CreateWebRequest(RSSFEED);
XmlTextReader rssReader = new XmlTextReader(webRequest.GetResponse().GetResponseStream()); XmlTextReader rssReader = new XmlTextReader(webRequest.GetResponse().GetResponseStream());
// Load the XML content into a XmlDocument // Load the XML content into a XmlDocument

View file

@ -58,7 +58,10 @@ namespace Greenshot.IniFile {
/// <summary> /// <summary>
/// Flag to specify if values have been changed /// Flag to specify if values have been changed
/// </summary> /// </summary>
public bool IsDirty = false; public bool IsDirty {
get;
set;
}
/// <summary> /// <summary>
/// Supply values we can't put as defaults /// Supply values we can't put as defaults