using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
+using System.Net.Http.Headers;
+using System.Runtime.Serialization.Json;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
+using System.Xml;
+using System.Xml.Linq;
using OpenTween.Connection;
namespace OpenTween.Api
}
}
+ public async Task<string> GetAccessTokenAsync(string username, string password)
+ {
+ var param = new Dictionary<string, string>
+ {
+ ["grant_type"] = "password",
+ ["username"] = username,
+ ["password"] = password,
+ };
+
+ var endpoint = new Uri(ApiBase, "/oauth/access_token");
+
+ using (var request = new HttpRequestMessage(HttpMethod.Post, endpoint))
+ using (var postContent = new FormUrlEncodedContent(param))
+ {
+ var authzParam = ApplicationSettings.BitlyClientId + ":" + ApplicationSettings.BitlyClientSecret;
+ request.Headers.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(Encoding.UTF8.GetBytes(authzParam)));
+
+ request.Content = postContent;
+
+ using (var response = await this.http.SendAsync(request).ConfigureAwait(false))
+ {
+ var responseBytes = await response.Content.ReadAsByteArrayAsync()
+ .ConfigureAwait(false);
+
+ return this.ParseOAuthCredential(responseBytes);
+ }
+ }
+ }
+
+ private string ParseOAuthCredential(byte[] responseBytes)
+ {
+ using (var jsonReader = JsonReaderWriterFactory.CreateJsonReader(responseBytes, XmlDictionaryReaderQuotas.Max))
+ {
+ var xElm = XElement.Load(jsonReader);
+
+ var statusCode = xElm.Element("status_code")?.Value ?? "200";
+ if (statusCode != "200")
+ {
+ var statusText = xElm.Element("status_txt")?.Value;
+ throw new WebApiException(statusText ?? $"status_code = {statusCode}");
+ }
+
+ var accessToken = xElm.Element("access_token")?.Value;
+ if (accessToken == null)
+ throw new WebApiException("Property `access_token` required");
+
+ return accessToken;
+ }
+ }
+
private IEnumerable<KeyValuePair<string, string>> CreateAccessTokenParams()
{
if (string.IsNullOrEmpty(this.EndUserAccessToken))
//=====================================================================
// bit.ly
- // https://bitly.com/a/account から取得できます。
+ // https://bitly.com/a/oauth_apps から取得できます。
/// <summary>
- /// bit.ly ログイン名
+ /// bit.ly Client ID
/// </summary>
- public const string BitlyLoginId = "opentween";
+ public const string BitlyClientId = "ddab8ec50f4459c315cbde9d923cf490923b6d2e";
/// <summary>
- /// bit.ly APIキー
+ /// bit.ly Client Secret
/// </summary>
- public const string BitlyApiKey = "R_76319a25e2420b8d2c42e812fe177d8b";
+ public const string BitlyClientSecret = "485c9d03dd264f8eeb4fc65d38e2762c4420cee7";
//=====================================================================
// TINAMI
-using System;
+// OpenTween - Client of Twitter
+// Copyright (c) 2017 kim_upsilon (@kim_upsilon) <https://upsilo.net/~upsilon/>
+// All rights reserved.
+//
+// This file is part of OpenTween.
+//
+// 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 3 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/>, or write to
+// the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
+// Boston, MA 02110-1301, USA.
+
+using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
}
/// <summary>
+ /// 認証に失敗しました ({0}) に類似しているローカライズされた文字列を検索します。
+ /// </summary>
+ internal static string BitlyAuthorize_ErrorText {
+ get {
+ return ResourceManager.GetString("BitlyAuthorize_ErrorText", resourceCulture);
+ }
+ }
+
+ /// <summary>
/// ブラウザの起動に失敗しました。エラーコード: {0} に類似しているローカライズされた文字列を検索します。
/// </summary>
internal static string BrowserStartFailed {
* If you run as administrator, operations to post images with D&D will be restricted.
* After running, the setting files of {0} will be able to modify only from administrator.</value>
</data>
+ <data name="BitlyAuthorize_ErrorText" xml:space="preserve">
+ <value>Failed to authorize. ({0})</value>
+ </data>
<data name="UrlConvert_BitlyAuthRequired" xml:space="preserve">
<value>To use Bitly, you must perform the Bitly authentication in settings dialog.</value>
</data>
* 管理者権限で実行するとD&Dで画像を投稿する操作が制限されます。
* {0}の設定ファイルが一般ユーザー権限で編集できなくなります。</value>
</data>
+ <data name="BitlyAuthorize_ErrorText" xml:space="preserve">
+ <value>認証に失敗しました ({0})</value>
+ </data>
<data name="UrlConvert_BitlyAuthRequired" xml:space="preserve">
<value>Bitlyを使用するには設定画面で認証情報を入力する必要があります</value>
</data>
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ShortUrlPanel));
this.ShortenTcoCheck = new System.Windows.Forms.CheckBox();
this.CheckTinyURL = new System.Windows.Forms.CheckBox();
- this.TextBitlyPw = new System.Windows.Forms.TextBox();
+ this.TextBitlyAccessToken = new System.Windows.Forms.TextBox();
this.CheckAutoConvertUrl = new System.Windows.Forms.CheckBox();
this.Label71 = new System.Windows.Forms.Label();
this.ComboBoxAutoShortUrlFirst = new System.Windows.Forms.ComboBox();
- this.Label76 = new System.Windows.Forms.Label();
this.Label77 = new System.Windows.Forms.Label();
- this.TextBitlyId = new System.Windows.Forms.TextBox();
+ this.ButtonBitlyAuthorize = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// ShortenTcoCheck
this.CheckTinyURL.Name = "CheckTinyURL";
this.CheckTinyURL.UseVisualStyleBackColor = true;
//
- // TextBitlyPw
+ // TextBitlyAccessToken
//
- resources.ApplyResources(this.TextBitlyPw, "TextBitlyPw");
- this.TextBitlyPw.Name = "TextBitlyPw";
+ resources.ApplyResources(this.TextBitlyAccessToken, "TextBitlyAccessToken");
+ this.TextBitlyAccessToken.Name = "TextBitlyAccessToken";
//
// CheckAutoConvertUrl
//
this.ComboBoxAutoShortUrlFirst.Name = "ComboBoxAutoShortUrlFirst";
this.ComboBoxAutoShortUrlFirst.SelectedIndexChanged += new System.EventHandler(this.ComboBoxAutoShortUrlFirst_SelectedIndexChanged);
//
- // Label76
- //
- resources.ApplyResources(this.Label76, "Label76");
- this.Label76.Name = "Label76";
- //
// Label77
//
resources.ApplyResources(this.Label77, "Label77");
this.Label77.Name = "Label77";
//
- // TextBitlyId
+ // ButtonBitlyAuthorize
//
- resources.ApplyResources(this.TextBitlyId, "TextBitlyId");
- this.TextBitlyId.Name = "TextBitlyId";
+ resources.ApplyResources(this.ButtonBitlyAuthorize, "ButtonBitlyAuthorize");
+ this.ButtonBitlyAuthorize.Name = "ButtonBitlyAuthorize";
+ this.ButtonBitlyAuthorize.UseVisualStyleBackColor = true;
+ this.ButtonBitlyAuthorize.Click += new System.EventHandler(this.ButtonBitlyAuthorize_Click);
//
// ShortUrlPanel
//
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
this.Controls.Add(this.ShortenTcoCheck);
this.Controls.Add(this.CheckTinyURL);
- this.Controls.Add(this.TextBitlyPw);
+ this.Controls.Add(this.TextBitlyAccessToken);
this.Controls.Add(this.CheckAutoConvertUrl);
this.Controls.Add(this.Label71);
this.Controls.Add(this.ComboBoxAutoShortUrlFirst);
- this.Controls.Add(this.Label76);
+ this.Controls.Add(this.ButtonBitlyAuthorize);
this.Controls.Add(this.Label77);
- this.Controls.Add(this.TextBitlyId);
this.Name = "ShortUrlPanel";
this.ResumeLayout(false);
this.PerformLayout();
internal System.Windows.Forms.CheckBox ShortenTcoCheck;
internal System.Windows.Forms.CheckBox CheckTinyURL;
- internal System.Windows.Forms.TextBox TextBitlyPw;
internal System.Windows.Forms.CheckBox CheckAutoConvertUrl;
internal System.Windows.Forms.Label Label71;
internal System.Windows.Forms.ComboBox ComboBoxAutoShortUrlFirst;
- internal System.Windows.Forms.Label Label76;
internal System.Windows.Forms.Label Label77;
- internal System.Windows.Forms.TextBox TextBitlyId;
+ private System.Windows.Forms.Button ButtonBitlyAuthorize;
+ private System.Windows.Forms.TextBox TextBitlyAccessToken;
}
}
using System.Linq;
using System.Text;
using System.Windows.Forms;
+using OpenTween.Api;
+using System.Threading.Tasks;
namespace OpenTween.Setting.Panel
{
this.ShortenTcoCheck.Enabled = this.CheckAutoConvertUrl.Checked;
this.ComboBoxAutoShortUrlFirst.SelectedIndex = (int)settingCommon.AutoShortUrlFirst;
- this.TextBitlyId.Text = settingCommon.BilyUser;
- this.TextBitlyPw.Text = settingCommon.BitlyPwd;
- this.TextBitlyId.Modified = false;
- this.TextBitlyPw.Modified = false;
+ this.TextBitlyAccessToken.Text = settingCommon.BitlyAccessToken;
+ this.TextBitlyAccessToken.Modified = false;
}
public void SaveConfig(SettingCommon settingCommon)
settingCommon.UrlConvertAuto = this.CheckAutoConvertUrl.Checked;
//settingCommon.ShortenTco = this.ShortenTcoCheck.Checked;
settingCommon.AutoShortUrlFirst = (MyCommon.UrlConverter)this.ComboBoxAutoShortUrlFirst.SelectedIndex;
- settingCommon.BilyUser = this.TextBitlyId.Text;
- settingCommon.BitlyPwd = this.TextBitlyPw.Text;
+ settingCommon.BitlyAccessToken = this.TextBitlyAccessToken.Text;
}
private void ComboBoxAutoShortUrlFirst_SelectedIndexChanged(object sender, EventArgs e)
if (ComboBoxAutoShortUrlFirst.SelectedIndex == (int)MyCommon.UrlConverter.Bitly ||
ComboBoxAutoShortUrlFirst.SelectedIndex == (int)MyCommon.UrlConverter.Jmp)
{
- Label76.Enabled = true;
Label77.Enabled = true;
- TextBitlyId.Enabled = true;
- TextBitlyPw.Enabled = true;
+ TextBitlyAccessToken.Enabled = true;
+ ButtonBitlyAuthorize.Enabled = true;
}
else
{
- Label76.Enabled = false;
Label77.Enabled = false;
- TextBitlyId.Enabled = false;
- TextBitlyPw.Enabled = false;
+ TextBitlyAccessToken.Enabled = false;
+ ButtonBitlyAuthorize.Enabled = false;
}
}
{
ShortenTcoCheck.Enabled = CheckAutoConvertUrl.Checked;
}
+
+ private void ButtonBitlyAuthorize_Click(object sender, EventArgs e)
+ {
+ using (var dialog = new LoginDialog())
+ {
+ const string DialogText = "Bitly Login";
+ dialog.Text = DialogText;
+
+ string accessToken = null;
+ dialog.LoginCallback = async () =>
+ {
+ try
+ {
+ var bitly = new BitlyApi();
+ accessToken = await bitly.GetAccessTokenAsync(dialog.LoginName, dialog.Password);
+ return true;
+ }
+ catch (WebApiException ex)
+ {
+ var text = string.Format(Properties.Resources.BitlyAuthorize_ErrorText, ex.Message);
+ MessageBox.Show(dialog, text, DialogText, MessageBoxButtons.OK, MessageBoxIcon.Error);
+ return false;
+ }
+ };
+
+ if (dialog.ShowDialog(this.ParentForm) == DialogResult.OK)
+ {
+ this.TextBitlyAccessToken.Text = accessToken;
+ }
+ }
+ }
}
}
<data name="Label71.Text" xml:space="preserve">
<value>Primary URLshorten service</value>
</data>
+ <data name="Label77.Size" type="System.Drawing.Size, System.Drawing">
+ <value>108, 12</value>
+ </data>
+ <data name="Label77.Text" xml:space="preserve">
+ <value>Bit.ly Access Token</value>
+ </data>
+ <data name="ButtonBitlyAuthorize.Text" xml:space="preserve">
+ <value>Authorize</value>
+ </data>
</root>
\ No newline at end of file
<value>95, 16</value>
</data>
<data name="ShortenTcoCheck.TabIndex" type="System.Int32, mscorlib">
- <value>18</value>
+ <value>2</value>
</data>
<data name="ShortenTcoCheck.Text" xml:space="preserve">
<value>t.coで短縮する</value>
<value>122, 16</value>
</data>
<data name="CheckTinyURL.TabIndex" type="System.Int32, mscorlib">
- <value>10</value>
+ <value>0</value>
</data>
<data name="CheckTinyURL.Text" xml:space="preserve">
<value>短縮URLを解決する</value>
<data name=">>CheckTinyURL.ZOrder" xml:space="preserve">
<value>1</value>
</data>
- <data name="TextBitlyPw.Location" type="System.Drawing.Point, System.Drawing">
- <value>419, 127</value>
+ <data name="TextBitlyAccessToken.Location" type="System.Drawing.Point, System.Drawing">
+ <value>249, 131</value>
</data>
- <data name="TextBitlyPw.Size" type="System.Drawing.Size, System.Drawing">
- <value>70, 19</value>
+ <data name="TextBitlyAccessToken.Size" type="System.Drawing.Size, System.Drawing">
+ <value>173, 19</value>
</data>
- <data name="TextBitlyPw.TabIndex" type="System.Int32, mscorlib">
- <value>17</value>
+ <data name="TextBitlyAccessToken.TabIndex" type="System.Int32, mscorlib">
+ <value>6</value>
</data>
- <data name=">>TextBitlyPw.Name" xml:space="preserve">
- <value>TextBitlyPw</value>
+ <data name=">>TextBitlyAccessToken.Name" xml:space="preserve">
+ <value>TextBitlyAccessToken</value>
</data>
- <data name=">>TextBitlyPw.Type" xml:space="preserve">
+ <data name=">>TextBitlyAccessToken.Type" xml:space="preserve">
<value>System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
- <data name=">>TextBitlyPw.Parent" xml:space="preserve">
+ <data name=">>TextBitlyAccessToken.Parent" xml:space="preserve">
<value>$this</value>
</data>
- <data name=">>TextBitlyPw.ZOrder" xml:space="preserve">
+ <data name=">>TextBitlyAccessToken.ZOrder" xml:space="preserve">
<value>2</value>
</data>
<data name="CheckAutoConvertUrl.AutoSize" type="System.Boolean, mscorlib">
<value>242, 16</value>
</data>
<data name="CheckAutoConvertUrl.TabIndex" type="System.Int32, mscorlib">
- <value>11</value>
+ <value>1</value>
</data>
<data name="CheckAutoConvertUrl.Text" xml:space="preserve">
<value>入力欄のURLを投稿する際に自動で短縮する</value>
<value>154, 12</value>
</data>
<data name="Label71.TabIndex" type="System.Int32, mscorlib">
- <value>12</value>
+ <value>3</value>
</data>
<data name="Label71.Text" xml:space="preserve">
<value>URL自動短縮で優先的に使用</value>
<value>246, 20</value>
</data>
<data name="ComboBoxAutoShortUrlFirst.TabIndex" type="System.Int32, mscorlib">
- <value>13</value>
+ <value>4</value>
</data>
<data name=">>ComboBoxAutoShortUrlFirst.Name" xml:space="preserve">
<value>ComboBoxAutoShortUrlFirst</value>
<data name=">>ComboBoxAutoShortUrlFirst.ZOrder" xml:space="preserve">
<value>5</value>
</data>
- <data name="Label76.AutoSize" type="System.Boolean, mscorlib">
- <value>True</value>
- </data>
- <data name="Label76.ImeMode" type="System.Windows.Forms.ImeMode, System.Windows.Forms">
- <value>NoControl</value>
- </data>
- <data name="Label76.Location" type="System.Drawing.Point, System.Drawing">
- <value>246, 130</value>
- </data>
- <data name="Label76.Size" type="System.Drawing.Size, System.Drawing">
- <value>16, 12</value>
- </data>
- <data name="Label76.TabIndex" type="System.Int32, mscorlib">
- <value>14</value>
- </data>
- <data name="Label76.Text" xml:space="preserve">
- <value>ID</value>
- </data>
- <data name=">>Label76.Name" xml:space="preserve">
- <value>Label76</value>
- </data>
- <data name=">>Label76.Type" xml:space="preserve">
- <value>System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
- </data>
- <data name=">>Label76.Parent" xml:space="preserve">
- <value>$this</value>
- </data>
- <data name=">>Label76.ZOrder" xml:space="preserve">
- <value>6</value>
- </data>
<data name="Label77.AutoSize" type="System.Boolean, mscorlib">
<value>True</value>
</data>
<value>NoControl</value>
</data>
<data name="Label77.Location" type="System.Drawing.Point, System.Drawing">
- <value>364, 130</value>
+ <value>23, 134</value>
</data>
<data name="Label77.Size" type="System.Drawing.Size, System.Drawing">
- <value>42, 12</value>
+ <value>106, 12</value>
</data>
<data name="Label77.TabIndex" type="System.Int32, mscorlib">
- <value>16</value>
+ <value>5</value>
</data>
<data name="Label77.Text" xml:space="preserve">
- <value>APIKey</value>
+ <value>Bit.ly アクセストークン</value>
</data>
<data name=">>Label77.Name" xml:space="preserve">
<value>Label77</value>
<data name=">>Label77.ZOrder" xml:space="preserve">
<value>7</value>
</data>
- <data name="TextBitlyId.Location" type="System.Drawing.Point, System.Drawing">
- <value>273, 127</value>
+ <data name="ButtonBitlyAuthorize.Location" type="System.Drawing.Point, System.Drawing">
+ <value>429, 129</value>
+ </data>
+ <data name="ButtonBitlyAuthorize.Size" type="System.Drawing.Size, System.Drawing">
+ <value>67, 23</value>
</data>
- <data name="TextBitlyId.Size" type="System.Drawing.Size, System.Drawing">
- <value>71, 19</value>
+ <data name="ButtonBitlyAuthorize.TabIndex" type="System.Int32, mscorlib">
+ <value>7</value>
</data>
- <data name="TextBitlyId.TabIndex" type="System.Int32, mscorlib">
- <value>15</value>
+ <data name="ButtonBitlyAuthorize.Text" xml:space="preserve">
+ <value>認可</value>
</data>
- <data name=">>TextBitlyId.Name" xml:space="preserve">
- <value>TextBitlyId</value>
+ <data name=">>ButtonBitlyAuthorize.Name" xml:space="preserve">
+ <value>ButtonBitlyAuthorize</value>
</data>
- <data name=">>TextBitlyId.Type" xml:space="preserve">
- <value>System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ <data name=">>ButtonBitlyAuthorize.Type" xml:space="preserve">
+ <value>System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
- <data name=">>TextBitlyId.Parent" xml:space="preserve">
+ <data name=">>ButtonBitlyAuthorize.Parent" xml:space="preserve">
<value>$this</value>
</data>
- <data name=">>TextBitlyId.ZOrder" xml:space="preserve">
- <value>8</value>
+ <data name=">>ButtonBitlyAuthorize.ZOrder" xml:space="preserve">
+ <value>6</value>
</data>
<metadata name="$this.Localizable" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>