diff --git a/GreenshotDropboxPlugin/DropboxDestination.cs b/GreenshotDropboxPlugin/DropboxDestination.cs
index 261ead03d..8b14de6cf 100644
--- a/GreenshotDropboxPlugin/DropboxDestination.cs
+++ b/GreenshotDropboxPlugin/DropboxDestination.cs
@@ -1,20 +1,20 @@
/*
* Greenshot - a free and open source screenshot tool
* Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel
- *
+ *
* For more information see: http://getgreenshot.org/
* The Greenshot project is hosted on GitHub https://github.com/greenshot/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 .
*/
@@ -32,7 +32,7 @@ namespace GreenshotDropboxPlugin {
public DropboxDestination(DropboxPlugin plugin) {
_plugin = plugin;
}
-
+
public override string Designation => "Dropbox";
public override string Description => Language.GetString("dropbox", LangKey.upload_menu_item);
@@ -43,8 +43,8 @@ namespace GreenshotDropboxPlugin {
return (Image)resources.GetObject("Dropbox");
}
}
-
- public override ExportInformation ExportCapture(bool manually, ISurface surface, ICaptureDetails captureDetails) {
+
+ public override ExportInformation ExportCapture(bool manually, ISurface surface, ICaptureDetails captureDetails) {
ExportInformation exportInformation = new ExportInformation(Designation, Description);
bool uploaded = _plugin.Upload(captureDetails, surface, out var uploadUrl);
if (uploaded) {
diff --git a/GreenshotDropboxPlugin/DropboxPlugin.cs b/GreenshotDropboxPlugin/DropboxPlugin.cs
index 3ee7b73cc..bf8842ecb 100644
--- a/GreenshotDropboxPlugin/DropboxPlugin.cs
+++ b/GreenshotDropboxPlugin/DropboxPlugin.cs
@@ -1,27 +1,26 @@
/*
* Greenshot - a free and open source screenshot tool
* Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel
- *
+ *
* For more information see: http://getgreenshot.org/
* The Greenshot project is hosted on GitHub https://github.com/greenshot/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 .
*/
using System;
using System.ComponentModel;
using System.Drawing;
-using System.IO;
using System.Windows.Forms;
using GreenshotPlugin.Controls;
using GreenshotPlugin.Core;
@@ -102,20 +101,16 @@ namespace GreenshotDropboxPlugin {
public bool Upload(ICaptureDetails captureDetails, ISurface surfaceToUpload, out string uploadUrl) {
uploadUrl = null;
SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(_config.UploadFormat, _config.UploadJpegQuality, false);
- try {
- string dropboxUrl = null;
- new PleaseWaitForm().ShowAndWait("Dropbox", Language.GetString("dropbox", LangKey.communication_wait),
+ try
+ {
+ bool result = false;
+ new PleaseWaitForm().ShowAndWait("Dropbox", Language.GetString("dropbox", LangKey.communication_wait),
delegate
{
- string filename = Path.GetFileName(FilenameHelper.GetFilename(_config.UploadFormat, captureDetails));
- dropboxUrl = DropboxUtils.UploadToDropbox(surfaceToUpload, outputSettings, filename);
+ result = DropboxUtils.UploadToDropbox(surfaceToUpload, outputSettings, captureDetails);
}
);
- if (dropboxUrl == null) {
- return false;
- }
- uploadUrl = dropboxUrl;
- return true;
+ return result;
} catch (Exception e) {
Log.Error(e);
MessageBox.Show(Language.GetString("dropbox", LangKey.upload_failure) + " " + e.Message);
diff --git a/GreenshotDropboxPlugin/DropboxUtils.cs b/GreenshotDropboxPlugin/DropboxUtils.cs
index c864c8cd3..eeb2b6405 100644
--- a/GreenshotDropboxPlugin/DropboxUtils.cs
+++ b/GreenshotDropboxPlugin/DropboxUtils.cs
@@ -20,11 +20,13 @@
*/
using System;
using System.Collections.Generic;
+using System.IO;
using GreenshotPlugin.Core;
using GreenshotPlugin.Core.OAuth;
using GreenshotPlugin.IniFile;
using GreenshotPlugin.Interfaces;
using GreenshotPlugin.Interfaces.Plugin;
+using Newtonsoft.Json;
namespace GreenshotDropboxPlugin {
///
@@ -37,11 +39,11 @@ namespace GreenshotDropboxPlugin {
private DropboxUtils() {
}
- public static string UploadToDropbox(ISurface surfaceToUpload, SurfaceOutputSettings outputSettings, string filename) {
-
+ public static bool UploadToDropbox(ISurface surfaceToUpload, SurfaceOutputSettings outputSettings, ICaptureDetails captureDetails)
+ {
var oauth2Settings = new OAuth2Settings
{
- AuthUrlPattern = "https://api.dropbox.com/oauth2/authorize?response_type=token&client_id={ClientId}&state={State}&redirect_uri={RedirectUrl}&token_access_type=offline",
+ AuthUrlPattern = "https://api.dropbox.com/oauth2/authorize?response_type=token&client_id={ClientId}&state={State}&redirect_uri={RedirectUrl}",
TokenUrl = "https://api.dropbox.com/oauth2/token",
RedirectUrl = "https://getgreenshot.org/authorize/dropbox",
CloudServiceName = "Dropbox",
@@ -55,20 +57,28 @@ namespace GreenshotDropboxPlugin {
try
{
+ string filename = Path.GetFileName(FilenameHelper.GetFilename(DropboxConfig.UploadFormat, captureDetails));
SurfaceContainer image = new SurfaceContainer(surfaceToUpload, outputSettings, filename);
- IDictionary parameters = new Dictionary
+ IDictionary arguments = new Dictionary
{
- { "file", image },
{ "autorename", true },
- { "mute", true},
- { "path", filename}
+ { "mute", true },
+ { "path", "/" + filename.Replace(Path.DirectorySeparatorChar, '\\')}
};
- var webRequest = OAuth2Helper.CreateOAuth2WebRequest(HTTPMethod.POST, "https://api.dropbox.com//2/files/upload", oauth2Settings);
- NetworkHelper.WriteMultipartFormData(webRequest, parameters);
- var response = NetworkHelper.GetResponseAsString(webRequest);
- Log.DebugFormat("Upload response: {0}", response);
- } catch (Exception ex) {
+ IDictionary headers = new Dictionary
+ {
+ { "Dropbox-API-Arg", JsonConvert.SerializeObject(arguments)}
+ };
+ var webRequest = OAuth2Helper.CreateOAuth2WebRequest(HTTPMethod.POST, "https://content.dropboxapi.com/2/files/upload", oauth2Settings);
+
+ NetworkHelper.Post(webRequest, headers, image);
+ var responseString = NetworkHelper.GetResponseAsString(webRequest);
+ Log.DebugFormat("Upload response: {0}", responseString);
+ var response = JsonConvert.DeserializeObject>(responseString);
+ return response.ContainsKey("id");
+ }
+ catch (Exception ex) {
Log.Error("Upload error: ", ex);
throw;
} finally {
@@ -78,7 +88,6 @@ namespace GreenshotDropboxPlugin {
DropboxConfig.IsDirty = true;
IniConfig.Save();
}
- return null;
- }
+ }
}
}
diff --git a/GreenshotPlugin/Core/NetworkHelper.cs b/GreenshotPlugin/Core/NetworkHelper.cs
index c3fcff8ab..8d275cf21 100644
--- a/GreenshotPlugin/Core/NetworkHelper.cs
+++ b/GreenshotPlugin/Core/NetworkHelper.cs
@@ -358,6 +358,84 @@ namespace GreenshotPlugin.Core {
WriteMultipartFormData(formDataStream, boundary, postParameters);
}
+
+ ///
+ /// Post content HttpWebRequest
+ ///
+ /// HttpWebRequest to write the multipart form data to
+ /// IDictionary with the headers
+ /// IBinaryContainer
+ public static void Post(HttpWebRequest webRequest, IDictionary headers, IBinaryContainer binaryContainer = null)
+ {
+ foreach (var header in headers)
+ {
+ switch (header.Key)
+ {
+ case "Content-Type":
+ webRequest.ContentType = header.Value as string;
+ break;
+ case "Accept":
+ webRequest.Accept = header.Value as string;
+ break;
+ default:
+ webRequest.Headers.Add(header.Key, Convert.ToString(header.Value));
+ break;
+ }
+ }
+ if (!headers.ContainsKey("Content-Type"))
+ {
+ webRequest.ContentType = "application/octet-stream";
+ }
+
+ if (binaryContainer != null)
+ {
+ using var requestStream = webRequest.GetRequestStream();
+ binaryContainer.WriteToStream(requestStream);
+ }
+ }
+
+ ///
+ /// Post content HttpWebRequest
+ ///
+ /// HttpWebRequest to write the multipart form data to
+ /// IDictionary with the headers
+ /// string
+ public static void Post(HttpWebRequest webRequest, IDictionary headers, string jsonString)
+ {
+ if (headers != null)
+ {
+ foreach (var header in headers)
+ {
+ switch (header.Key)
+ {
+ case "Content-Type":
+ webRequest.ContentType = header.Value as string;
+ break;
+ case "Accept":
+ webRequest.Accept = header.Value as string;
+ break;
+ default:
+ webRequest.Headers.Add(header.Key, Convert.ToString(header.Value));
+ break;
+ }
+ }
+ if (!headers.ContainsKey("Content-Type"))
+ {
+ webRequest.ContentType = "application/json";
+ }
+ }
+ else
+ {
+ webRequest.ContentType = "application/json";
+ }
+
+ if (jsonString != null)
+ {
+ using var requestStream = webRequest.GetRequestStream();
+ using var streamWriter = new StreamWriter(requestStream);
+ streamWriter.Write(jsonString);
+ }
+ }
///
/// Write Multipart Form Data to the HttpListenerResponse
///
diff --git a/GreenshotPlugin/Core/OAuth/OAuth2Helper.cs b/GreenshotPlugin/Core/OAuth/OAuth2Helper.cs
index 2436fb90d..b80d62b3d 100644
--- a/GreenshotPlugin/Core/OAuth/OAuth2Helper.cs
+++ b/GreenshotPlugin/Core/OAuth/OAuth2Helper.cs
@@ -51,7 +51,6 @@ namespace GreenshotPlugin.Core.OAuth {
// Use the returned code to get a refresh code
{ Code, settings.Code },
{ ClientId, settings.ClientId },
- { RedirectUri, settings.RedirectUrl },
{ ClientSecret, settings.ClientSecret },
{ GrantType, AuthorizationCode }
};
@@ -194,29 +193,29 @@ namespace GreenshotPlugin.Core.OAuth {
}
///
- /// Authenticate by using the mode specified in the settings
+ /// Authorize by using the mode specified in the settings
///
/// OAuth2Settings
/// false if it was canceled, true if it worked, exception if not
- public static bool Authenticate(OAuth2Settings settings) {
+ public static bool Authorize(OAuth2Settings settings) {
var completed = settings.AuthorizeMode switch
{
- OAuth2AuthorizeMode.LocalServer => AuthenticateViaLocalServer(settings),
- OAuth2AuthorizeMode.EmbeddedBrowser => AuthenticateViaEmbeddedBrowser(settings),
- OAuth2AuthorizeMode.JsonReceiver => AuthenticateViaDefaultBrowser(settings),
+ OAuth2AuthorizeMode.LocalServer => AuthorizeViaLocalServer(settings),
+ OAuth2AuthorizeMode.EmbeddedBrowser => AuthorizeViaEmbeddedBrowser(settings),
+ OAuth2AuthorizeMode.JsonReceiver => AuthorizeViaDefaultBrowser(settings),
_ => throw new NotImplementedException($"Authorize mode '{settings.AuthorizeMode}' is not 'yet' implemented."),
};
return completed;
}
///
- /// Authenticate via the default browser, via the Greenshot website.
+ /// Authorize via the default browser, via the Greenshot website.
/// It will wait for a Json post.
/// If this works, return the code
///
/// OAuth2Settings with the Auth / Token url etc
/// true if completed, false if canceled
- private static bool AuthenticateViaDefaultBrowser(OAuth2Settings settings)
+ private static bool AuthorizeViaDefaultBrowser(OAuth2Settings settings)
{
var codeReceiver = new LocalJsonReceiver();
IDictionary result = codeReceiver.ReceiveCode(settings);
@@ -258,20 +257,21 @@ namespace GreenshotPlugin.Core.OAuth {
}
if (result.TryGetValue(Code, out var code) && !string.IsNullOrEmpty(code))
{
- settings.Code = code;
+ settings.Code = code;
GenerateRefreshToken(settings);
+ return !string.IsNullOrEmpty(settings.AccessToken);
}
return true;
}
///
- /// Authenticate via an embedded browser
+ /// Authorize via an embedded browser
/// If this works, return the code
///
/// OAuth2Settings with the Auth / Token url etc
/// true if completed, false if canceled
- private static bool AuthenticateViaEmbeddedBrowser(OAuth2Settings settings) {
+ private static bool AuthorizeViaEmbeddedBrowser(OAuth2Settings settings) {
if (string.IsNullOrEmpty(settings.CloudServiceName)) {
throw new ArgumentNullException(nameof(settings.CloudServiceName));
}
@@ -290,12 +290,12 @@ namespace GreenshotPlugin.Core.OAuth {
}
///
- /// Authenticate via a local server by using the LocalServerCodeReceiver
+ /// Authorize via a local server by using the LocalServerCodeReceiver
/// If this works, return the code
///
/// OAuth2Settings with the Auth / Token url etc
/// true if completed
- private static bool AuthenticateViaLocalServer(OAuth2Settings settings) {
+ private static bool AuthorizeViaLocalServer(OAuth2Settings settings) {
var codeReceiver = new LocalServerCodeReceiver();
IDictionary result = codeReceiver.ReceiveCode(settings);
@@ -335,7 +335,7 @@ namespace GreenshotPlugin.Core.OAuth {
public static void CheckAndAuthenticateOrRefresh(OAuth2Settings settings) {
// Get Refresh / Access token
if (string.IsNullOrEmpty(settings.RefreshToken)) {
- if (!Authenticate(settings)) {
+ if (!Authorize(settings)) {
throw new Exception("Authentication cancelled");
}
}
@@ -343,7 +343,7 @@ namespace GreenshotPlugin.Core.OAuth {
GenerateAccessToken(settings);
// Get Refresh / Access token
if (string.IsNullOrEmpty(settings.RefreshToken)) {
- if (!Authenticate(settings)) {
+ if (!Authorize(settings)) {
throw new Exception("Authentication cancelled");
}
GenerateAccessToken(settings);
diff --git a/GreenshotPlugin/Core/OAuth/OAuth2Settings.cs b/GreenshotPlugin/Core/OAuth/OAuth2Settings.cs
index 1b8bd1042..57b566aaa 100644
--- a/GreenshotPlugin/Core/OAuth/OAuth2Settings.cs
+++ b/GreenshotPlugin/Core/OAuth/OAuth2Settings.cs
@@ -137,6 +137,10 @@ namespace GreenshotPlugin.Core.OAuth
///
public bool IsAccessTokenExpired {
get {
+ if (AccessTokenExpires == default)
+ {
+ return false;
+ }
bool expired = true;
if (!string.IsNullOrEmpty(AccessToken)) {
expired = DateTimeOffset.Now.AddSeconds(60) > AccessTokenExpires;