diff --git a/ShareX/UploadTask.cs b/ShareX/UploadTask.cs index 28a90ffbc..4238e8b0e 100644 --- a/ShareX/UploadTask.cs +++ b/ShareX/UploadTask.cs @@ -946,6 +946,11 @@ public UploadResult UploadFile(Stream stream, string fileName) case FileDestination.MediaCrush: fileUploader = new MediaCrushUploader(); break; + case FileDestination.MediaFire: + fileUploader = new MediaFire(APIKeys.MediaFireAppId, APIKeys.MediaFireApiKey, + Program.UploadersConfig.MediaFireUsername, Program.UploadersConfig.MediaFirePassword, + NameParser.Parse(NameParserType.URL, Program.UploadersConfig.MediaFirePath)); + break; } if (fileUploader != null) diff --git a/UploadersLib/APIKeys/APIKeys.cs b/UploadersLib/APIKeys/APIKeys.cs index b71803cce..18a89a3a4 100644 --- a/UploadersLib/APIKeys/APIKeys.cs +++ b/UploadersLib/APIKeys/APIKeys.cs @@ -52,6 +52,8 @@ public static partial class APIKeys public static string SendSpaceKey = ""; public static string Ge_ttKey = ""; public static string JiraConsumerKey = ""; + public static string MediaFireAppId = ""; + public static string MediaFireApiKey = ""; // Text Uploaders public static string PastebinKey = ""; diff --git a/UploadersLib/Enums.cs b/UploadersLib/Enums.cs index 4e97b9b07..dd2e413b7 100644 --- a/UploadersLib/Enums.cs +++ b/UploadersLib/Enums.cs @@ -117,7 +117,9 @@ public enum FileDestination [Description("Email")] Email, [Description("Custom file uploader")] - CustomFileUploader + CustomFileUploader, + [Description("MediaFire")] + MediaFire } [Description("URL shorteners"), DefaultValue(UrlShortenerType.BITLY)] diff --git a/UploadersLib/Favicons/MediaFire.ico b/UploadersLib/Favicons/MediaFire.ico new file mode 100644 index 000000000..7b4acd43d Binary files /dev/null and b/UploadersLib/Favicons/MediaFire.ico differ diff --git a/UploadersLib/FileUploaders/MediaFire.cs b/UploadersLib/FileUploaders/MediaFire.cs new file mode 100644 index 000000000..c4fbf46a1 --- /dev/null +++ b/UploadersLib/FileUploaders/MediaFire.cs @@ -0,0 +1,198 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Xml.Serialization; + +namespace UploadersLib.FileUploaders +{ + public sealed class MediaFire : FileUploader + { + private static readonly string _apiUrl = "https://www.mediafire.com/api/"; + private static readonly string _viewUrl = "http://www.mediafire.com/view/?"; + private static readonly int _pollInterval = 3000; + private readonly string _appId, _apiKey, _user, _pasw, _path; + private string _sessionToken, _signatureTime; + private int _signatureKey; + + public MediaFire(string appId, string apiKey, string user, string pasw, string path) + { + _appId = appId; + _apiKey = apiKey; + _user = user; + _pasw = pasw; + _path = path; + } + + public override UploadResult Upload(Stream stream, string fileName) + { + GetSessionToken(); + string key = SimpleUpload(stream, fileName); + string quickKey = null; + while ((quickKey = PollUpload(key, fileName)) == null) System.Threading.Thread.Sleep(_pollInterval); + return new UploadResult() { IsSuccess = true, URL = _viewUrl + quickKey }; + } + + private void GetSessionToken() + { + var args = new Dictionary(); + args.Add("email", _user); + args.Add("password", _pasw); + args.Add("application_id", _appId); + args.Add("token_version", "2"); + args.Add("response_format", "json"); + args.Add("signature", GetInitSignature()); + string respStr = SendRequest(HttpMethod.POST, _apiUrl + "user/get_session_token.php", args); + GetSessionTokenResponse resp = DeserializeResponse(respStr); + EnsureSuccess(resp); + if (resp.session_token == null || resp.time == null || resp.secret_key == null) + throw new IOException("Invalid response"); + _sessionToken = resp.session_token; + _signatureTime = resp.time; + _signatureKey = (int)resp.secret_key; + } + + private string SimpleUpload(Stream stream, string fileName) + { + var args = new Dictionary(); + args.Add("session_token", _sessionToken); + args.Add("path", _path); + args.Add("response_format", "json"); + args.Add("signature", GetSignature("upload/simple.php", args)); + string url = CreateQuery(_apiUrl + "upload/simple.php", args); + UploadResult res = UploadData(stream, url, fileName, "Filedata"); + if (!res.IsSuccess) throw new IOException(res.ErrorsToString()); + SimpleUploadResponse resp = DeserializeResponse(res.Response); + EnsureSuccess(resp); + if (resp.doupload.result != 0 || resp.doupload.key == null) throw new IOException("Invalid response"); + return resp.doupload.key; + } + + private string PollUpload(string uploadKey, string fileName) + { + var args = new Dictionary(); + args.Add("session_token", _sessionToken); + args.Add("key", uploadKey); + args.Add("filename", fileName); + args.Add("response_format", "json"); + args.Add("signature", GetSignature("upload/poll_upload.php", args)); + string respStr = SendRequest(HttpMethod.POST, _apiUrl + "upload/poll_upload.php", args); + PollUploadResponse resp = DeserializeResponse(respStr); + EnsureSuccess(resp); + if (resp.doupload.result == null || resp.doupload.status == null) throw new IOException("Invalid response"); + if (resp.doupload.result != 0 || resp.doupload.fileerror != null) { + throw new IOException(string.Format("Couldn't upload the file: {0}", resp.doupload.description + ?? "Unknown error")); + } + if (resp.doupload.status == 99) { + if (resp.doupload.quickkey == null) throw new IOException("Invalid response"); + return resp.doupload.quickkey; + } + return null; + } + + private void EnsureSuccess(MFResponse resp) + { + if (resp.result != "Success") + throw new IOException(string.Format("Couldn't upload the file: {0}", resp.message ?? "Unknown error")); + if (resp.new_key == "yes") NextSignatureKey(); + } + + private string GetInitSignature() + { + string signatureStr = _user + _pasw + _appId + _apiKey; + byte[] signatureBytes = Encoding.ASCII.GetBytes(signatureStr); + System.Security.Cryptography.SHA1 sha1Gen = System.Security.Cryptography.SHA1.Create(); + byte[] sha1Bytes = sha1Gen.ComputeHash(signatureBytes); + return BytesToString(sha1Bytes); + } + + private string GetSignature(string urlSuffix, Dictionary args) + { + string keyStr = (_signatureKey % 256).ToString(System.Globalization.CultureInfo.InvariantCulture); + string urlStr = CreateNonEscapedQuery("/api/" + urlSuffix, args); + string signatureStr = keyStr + _signatureTime + urlStr; + byte[] signatureBytes = Encoding.ASCII.GetBytes(signatureStr); + System.Security.Cryptography.MD5 md5gen = System.Security.Cryptography.MD5.Create(); + byte[] md5Bytes = md5gen.ComputeHash(signatureBytes); + return BytesToString(md5Bytes); + } + + void NextSignatureKey() + { + _signatureKey = (int)(((long)_signatureKey * 16807) % 2147483647); + } + + private T DeserializeResponse(string s) where T : new() + { + var refObj = new { response = new T() }; + var obj = JsonConvert.DeserializeObject(s, refObj.GetType()); + return (T)obj.GetType().GetProperty("response").GetValue(obj, null); + } + + private static char IntToChar(int x) + { + if (x < 10) return (char)(x + '0'); + return (char)(x - 10 + 'a'); + } + + private static string BytesToString(byte[] b) + { + char[] res = new char[b.Length * 2]; + for (int i = 0; i < b.Length; ++i) { + res[2 * i] = IntToChar(b[i] >> 4); + res[2 * i + 1] = IntToChar(b[i] & 0xf); + } + return new string(res); + } + + private static string CreateNonEscapedQuery(string url, Dictionary args) + { + if (args != null && args.Count > 0) + return url + "?" + string.Join("&", args.Select(x => x.Key + "=" + x.Value).ToArray()); + return url; + } + + private class MFResponse + { + public string result { get; set; } + public int? error { get; set; } + public string message { get; set; } + public string new_key { get; set; } + } + + private class GetSessionTokenResponse : MFResponse + { + public string session_token { get; set; } + public int? secret_key { get; set; } + public string time { get; set; } + } + + private class SimpleUploadResponse : MFResponse + { + public DoUpload doupload { get; set; } + + public class DoUpload + { + public int? result { get; set; } + public string key { get; set; } + } + } + + private class PollUploadResponse : MFResponse + { + public DoUpload doupload { get; set; } + + public class DoUpload + { + public int? result { get; set; } + public int? status { get; set; } + public string description { get; set; } + public int? fileerror { get; set; } + public string quickkey { get; set; } + } + } + } +} diff --git a/UploadersLib/Forms/UploadersConfigForm.Designer.cs b/UploadersLib/Forms/UploadersConfigForm.Designer.cs index 3f4e778ee..82412aafc 100644 --- a/UploadersLib/Forms/UploadersConfigForm.Designer.cs +++ b/UploadersLib/Forms/UploadersConfigForm.Designer.cs @@ -380,6 +380,13 @@ private void InitializeComponent() this.lblWidthHint = new System.Windows.Forms.Label(); this.actRapidShareAccountType = new UploadersLib.AccountTypeControl(); this.cbImgurDirectLink = new System.Windows.Forms.CheckBox(); + this.tpMediaFire = new System.Windows.Forms.TabPage(); + this.txtMediaFirePassword = new System.Windows.Forms.TextBox(); + this.txtMediaFireUsername = new System.Windows.Forms.TextBox(); + this.lblMediaFirePassword = new System.Windows.Forms.Label(); + this.lblMediaFireUsername = new System.Windows.Forms.Label(); + this.lblMediaFirePath = new System.Windows.Forms.Label(); + this.txtMediaFirePath = new System.Windows.Forms.TextBox(); this.tpOtherUploaders.SuspendLayout(); this.tcOtherUploaders.SuspendLayout(); this.tpCustomUploaders.SuspendLayout(); @@ -435,6 +442,7 @@ private void InitializeComponent() this.gbPhotobucketAlbums.SuspendLayout(); this.gbPhotobucketUserAccount.SuspendLayout(); this.tpPicasa.SuspendLayout(); + this.tpMediaFire.SuspendLayout(); this.tcUploaders.SuspendLayout(); this.SuspendLayout(); // @@ -1388,6 +1396,7 @@ private void InitializeComponent() this.tcFileUploaders.Controls.Add(this.tpJira); this.tcFileUploaders.Controls.Add(this.tpEmail); this.tcFileUploaders.Controls.Add(this.tpSharedFolder); + this.tcFileUploaders.Controls.Add(this.tpMediaFire); this.tcFileUploaders.Dock = System.Windows.Forms.DockStyle.Fill; this.tcFileUploaders.Location = new System.Drawing.Point(3, 3); this.tcFileUploaders.Multiline = true; @@ -3169,6 +3178,74 @@ private void InitializeComponent() this.ucLocalhostAccounts.Name = "ucLocalhostAccounts"; this.ucLocalhostAccounts.Size = new System.Drawing.Size(792, 448); this.ucLocalhostAccounts.TabIndex = 6; + // + // tpMediaFire + // + this.tpMediaFire.Controls.Add(this.txtMediaFirePath); + this.tpMediaFire.Controls.Add(this.lblMediaFirePath); + this.tpMediaFire.Controls.Add(this.txtMediaFirePassword); + this.tpMediaFire.Controls.Add(this.txtMediaFireUsername); + this.tpMediaFire.Controls.Add(this.lblMediaFirePassword); + this.tpMediaFire.Controls.Add(this.lblMediaFireUsername); + this.tpMediaFire.Location = new System.Drawing.Point(4, 40); + this.tpMediaFire.Name = "tpMediaFire"; + this.tpMediaFire.Padding = new System.Windows.Forms.Padding(3); + this.tpMediaFire.Size = new System.Drawing.Size(972, 475); + this.tpMediaFire.TabIndex = 16; + this.tpMediaFire.Text = "MediaFire"; + this.tpMediaFire.UseVisualStyleBackColor = true; + // + // txtMediaFirePassword + // + this.txtMediaFirePassword.Location = new System.Drawing.Point(80, 52); + this.txtMediaFirePassword.Name = "txtMediaFirePassword"; + this.txtMediaFirePassword.PasswordChar = '*'; + this.txtMediaFirePassword.Size = new System.Drawing.Size(136, 20); + this.txtMediaFirePassword.TabIndex = 3; + this.txtMediaFirePassword.TextChanged += new System.EventHandler(this.txtMediaFirePassword_TextChanged); + // + // txtMediaFireUsername + // + this.txtMediaFireUsername.Location = new System.Drawing.Point(80, 20); + this.txtMediaFireUsername.Name = "txtMediaFireUsername"; + this.txtMediaFireUsername.Size = new System.Drawing.Size(136, 20); + this.txtMediaFireUsername.TabIndex = 2; + this.txtMediaFireUsername.TextChanged += new System.EventHandler(this.txtMediaFireUsername_TextChanged); + // + // lblMediaFirePassword + // + this.lblMediaFirePassword.AutoSize = true; + this.lblMediaFirePassword.Location = new System.Drawing.Point(16, 56); + this.lblMediaFirePassword.Name = "lblMediaFirePassword"; + this.lblMediaFirePassword.Size = new System.Drawing.Size(56, 13); + this.lblMediaFirePassword.TabIndex = 1; + this.lblMediaFirePassword.Text = "Password:"; + // + // lblMediaFireUsername + // + this.lblMediaFireUsername.AutoSize = true; + this.lblMediaFireUsername.Location = new System.Drawing.Point(16, 24); + this.lblMediaFireUsername.Name = "lblMediaFireUsername"; + this.lblMediaFireUsername.Size = new System.Drawing.Size(58, 13); + this.lblMediaFireUsername.TabIndex = 0; + this.lblMediaFireUsername.Text = "Username:"; + // + // lblMediaFirePath + // + this.lblMediaFirePath.AutoSize = true; + this.lblMediaFirePath.Location = new System.Drawing.Point(16, 88); + this.lblMediaFirePath.Name = "lblMediaFirePath"; + this.lblMediaFirePath.Size = new System.Drawing.Size(68, 13); + this.lblMediaFirePath.TabIndex = 4; + this.lblMediaFirePath.Text = "Upload path:"; + // + // txtMediaFirePath + // + this.txtMediaFirePath.Location = new System.Drawing.Point(88, 85); + this.txtMediaFirePath.Name = "txtMediaFirePath"; + this.txtMediaFirePath.Size = new System.Drawing.Size(248, 20); + this.txtMediaFirePath.TabIndex = 5; + this.txtMediaFirePath.TextChanged += new System.EventHandler(this.txtMediaFirePath_TextChanged); // // btnCopyShowFiles // @@ -4157,6 +4234,8 @@ private void InitializeComponent() ((System.ComponentModel.ISupportInitialize)(this.nudEmailSmtpPort)).EndInit(); this.tpSharedFolder.ResumeLayout(false); this.tpSharedFolder.PerformLayout(); + this.tpMediaFire.ResumeLayout(false); + this.tpMediaFire.PerformLayout(); this.tpTextUploaders.ResumeLayout(false); this.tcTextUploaders.ResumeLayout(false); this.tpPastebin.ResumeLayout(false); @@ -4543,5 +4622,12 @@ private void InitializeComponent() private System.Windows.Forms.Label lblAdflyAPIKEY; private System.Windows.Forms.LinkLabel llAdflyLink; private System.Windows.Forms.CheckBox cbImgurDirectLink; + private System.Windows.Forms.TabPage tpMediaFire; + private System.Windows.Forms.TextBox txtMediaFirePassword; + private System.Windows.Forms.TextBox txtMediaFireUsername; + private System.Windows.Forms.Label lblMediaFirePassword; + private System.Windows.Forms.Label lblMediaFireUsername; + private System.Windows.Forms.TextBox txtMediaFirePath; + private System.Windows.Forms.Label lblMediaFirePath; } } \ No newline at end of file diff --git a/UploadersLib/Forms/UploadersConfigForm.cs b/UploadersLib/Forms/UploadersConfigForm.cs index 505b647a8..28b36b039 100644 --- a/UploadersLib/Forms/UploadersConfigForm.cs +++ b/UploadersLib/Forms/UploadersConfigForm.cs @@ -100,6 +100,7 @@ private void FormSettings() uploadersImageList.Images.Add("Twitter", Resources.Twitter); uploadersImageList.Images.Add("ownCloud", Resources.OwnCloud); uploadersImageList.Images.Add("AdFly", Resources.AdFly); + uploadersImageList.Images.Add("MediaFire", Resources.MediaFire); tpImageShack.ImageKey = "ImageShack"; tpTinyPic.ImageKey = "TinyPic"; @@ -134,6 +135,7 @@ private void FormSettings() tpAmazonS3.ImageKey = "AmazonS3"; tpOwnCloud.ImageKey = "ownCloud"; tpAdFly.ImageKey = "AdFly"; + tpMediaFire.ImageKey = "MediaFire"; ttlvMain.ImageList = uploadersImageList; ttlvMain.MainTabControl = tcUploaders; @@ -142,6 +144,7 @@ private void FormSettings() NameParser.CreateCodesMenu(txtDropboxPath, ReplacementVariables.n, ReplacementVariables.t, ReplacementVariables.pn); NameParser.CreateCodesMenu(txtCopyPath, ReplacementVariables.n, ReplacementVariables.t, ReplacementVariables.pn); NameParser.CreateCodesMenu(txtAmazonS3ObjectPrefix, ReplacementVariables.n, ReplacementVariables.t, ReplacementVariables.pn); + NameParser.CreateCodesMenu(txtMediaFirePath, ReplacementVariables.n, ReplacementVariables.t, ReplacementVariables.pn); NameParser.CreateCodesMenu(txtCustomUploaderArgValue, ReplacementVariables.n); txtCustomUploaderLog.AddContextMenu(); @@ -488,6 +491,12 @@ public void LoadSettings(UploadersConfig uploadersConfig) cbOwnCloudCreateShare.Checked = Config.OwnCloudCreateShare; cbOwnCloudDirectLink.Checked = Config.OwnCloudDirectLink; + // MediaFire + + txtMediaFireUsername.Text = Config.MediaFireUsername; + txtMediaFirePassword.Text = Config.MediaFirePassword; + txtMediaFirePath.Text = Config.MediaFirePath; + #endregion File uploaders #region URL Shorteners @@ -1778,6 +1787,25 @@ private void SettingsGrid_LocalhostPropertyValueChanged(object s, PropertyValueC #endregion Shared folder + #region MediaFire + + private void txtMediaFireUsername_TextChanged(object sender, EventArgs e) + { + Config.MediaFireUsername = txtMediaFireUsername.Text; + } + + private void txtMediaFirePassword_TextChanged(object sender, EventArgs e) + { + Config.MediaFirePassword = txtMediaFirePassword.Text; + } + + private void txtMediaFirePath_TextChanged(object sender, EventArgs e) + { + Config.MediaFirePath = txtMediaFirePath.Text; + } + + #endregion + #endregion File Uploaders #region URL Shorteners diff --git a/UploadersLib/Properties/Resources.Designer.cs b/UploadersLib/Properties/Resources.Designer.cs index cd983f651..9be946ad4 100644 --- a/UploadersLib/Properties/Resources.Designer.cs +++ b/UploadersLib/Properties/Resources.Designer.cs @@ -300,6 +300,16 @@ internal class Resources { } } + /// + /// Looks up a localized resource of type System.Drawing.Icon similar to (Icon). + /// + internal static System.Drawing.Icon MediaFire { + get { + object obj = ResourceManager.GetObject("MediaFire", resourceCulture); + return ((System.Drawing.Icon)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Icon similar to (Icon). /// diff --git a/UploadersLib/Properties/Resources.resx b/UploadersLib/Properties/Resources.resx index aa866d89f..b31b15bdd 100644 --- a/UploadersLib/Properties/Resources.resx +++ b/UploadersLib/Properties/Resources.resx @@ -310,4 +310,7 @@ ..\favicons\adfly.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Favicons\MediaFire.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + \ No newline at end of file diff --git a/UploadersLib/UploadersConfig.cs b/UploadersLib/UploadersConfig.cs index 296403daa..b3c537b71 100644 --- a/UploadersLib/UploadersConfig.cs +++ b/UploadersLib/UploadersConfig.cs @@ -218,6 +218,12 @@ public class UploadersConfig : SettingsBase public bool OwnCloudCreateShare = true; public bool OwnCloudDirectLink = false; + // MediaFire + + public string MediaFireUsername = ""; + public string MediaFirePassword = ""; + public string MediaFirePath = ""; + #endregion File uploaders #region URL shorteners @@ -375,6 +381,8 @@ public bool IsValid(FileDestination destination) PushbulletSettings.DeviceList.IsValidIndex(PushbulletSettings.SelectedDevice); case FileDestination.OwnCloud: return !string.IsNullOrEmpty(OwnCloudHost) && !string.IsNullOrEmpty(OwnCloudUsername) && !string.IsNullOrEmpty(OwnCloudPassword); + case FileDestination.MediaFire: + return !string.IsNullOrEmpty(MediaFireUsername) && !string.IsNullOrEmpty(MediaFirePassword); } return true; diff --git a/UploadersLib/UploadersLib.csproj b/UploadersLib/UploadersLib.csproj index 6b4b16637..01ad35ebd 100644 --- a/UploadersLib/UploadersLib.csproj +++ b/UploadersLib/UploadersLib.csproj @@ -109,6 +109,7 @@ + @@ -426,6 +427,7 @@ +