From 6b9666e7932e6a5b2e9beade43db701e355f9faa Mon Sep 17 00:00:00 2001 From: Kimura Youichi Date: Tue, 26 Mar 2019 01:49:50 +0900 Subject: [PATCH] =?utf8?q?=E7=9F=AD=E7=B8=AEURL=E5=B1=95=E9=96=8B=E6=99=82?= =?utf8?q?=E3=81=ABHTTPS=E3=81=8C=E4=BD=BF=E7=94=A8=E3=81=A7=E3=81=8D?= =?utf8?q?=E3=82=8B=E3=83=89=E3=83=A1=E3=82=A4=E3=83=B3=E3=81=AF=E5=BC=B7?= =?utf8?q?=E5=88=B6=E7=9A=84=E3=81=ABHTTPS=E3=82=92=E4=BD=BF=E7=94=A8?= =?utf8?q?=E3=81=99=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- OpenTween.Tests/ShortUrlTest.cs | 114 +++++++++++++++++++++++++++----------- OpenTween/Resources/ChangeLog.txt | 1 + OpenTween/ShortUrl.cs | 37 +++++++++++++ 3 files changed, 120 insertions(+), 32 deletions(-) diff --git a/OpenTween.Tests/ShortUrlTest.cs b/OpenTween.Tests/ShortUrlTest.cs index fd1ed82d..2fed93b3 100644 --- a/OpenTween.Tests/ShortUrlTest.cs +++ b/OpenTween.Tests/ShortUrlTest.cs @@ -42,17 +42,17 @@ namespace OpenTween { var shortUrl = new ShortUrl(http); - // http://t.co/hoge1 -> http://example.com/hoge2 + // https://t.co/hoge1 -> http://example.com/hoge2 handler.Enqueue(x => { Assert.Equal(HttpMethod.Head, x.Method); - Assert.Equal(new Uri("http://t.co/hoge1"), x.RequestUri); + Assert.Equal(new Uri("https://t.co/hoge1"), x.RequestUri); return this.CreateRedirectResponse("http://example.com/hoge2"); }); Assert.Equal(new Uri("http://example.com/hoge2"), - await shortUrl.ExpandUrlAsync(new Uri("http://t.co/hoge1"))); + await shortUrl.ExpandUrlAsync(new Uri("https://t.co/hoge1"))); Assert.Equal(0, handler.QueueCount); } @@ -92,7 +92,7 @@ namespace OpenTween shortUrl.DisableExpanding = true; - // http://t.co/hoge1 -> http://example.com/hoge2 + // https://t.co/hoge1 -> http://example.com/hoge2 handler.Enqueue(x => { // このリクエストは実行されないはず @@ -100,8 +100,8 @@ namespace OpenTween return this.CreateRedirectResponse("http://example.com/hoge2"); }); - Assert.Equal(new Uri("http://t.co/hoge1"), - await shortUrl.ExpandUrlAsync(new Uri("http://t.co/hoge1"))); + Assert.Equal(new Uri("https://t.co/hoge1"), + await shortUrl.ExpandUrlAsync(new Uri("https://t.co/hoge1"))); Assert.Equal(1, handler.QueueCount); } @@ -115,26 +115,26 @@ namespace OpenTween { var shortUrl = new ShortUrl(http); - // http://t.co/hoge1 -> http://bit.ly/hoge2 + // https://t.co/hoge1 -> https://bit.ly/hoge2 handler.Enqueue(x => { Assert.Equal(HttpMethod.Head, x.Method); - Assert.Equal(new Uri("http://t.co/hoge1"), x.RequestUri); + Assert.Equal(new Uri("https://t.co/hoge1"), x.RequestUri); - return this.CreateRedirectResponse("http://bit.ly/hoge2"); + return this.CreateRedirectResponse("https://bit.ly/hoge2"); }); - // http://bit.ly/hoge2 -> http://example.com/hoge3 + // https://bit.ly/hoge2 -> http://example.com/hoge3 handler.Enqueue(x => { Assert.Equal(HttpMethod.Head, x.Method); - Assert.Equal(new Uri("http://bit.ly/hoge2"), x.RequestUri); + Assert.Equal(new Uri("https://bit.ly/hoge2"), x.RequestUri); return this.CreateRedirectResponse("http://example.com/hoge3"); }); Assert.Equal(new Uri("http://example.com/hoge3"), - await shortUrl.ExpandUrlAsync(new Uri("http://t.co/hoge1"))); + await shortUrl.ExpandUrlAsync(new Uri("https://t.co/hoge1"))); Assert.Equal(0, handler.QueueCount); } @@ -148,25 +148,25 @@ namespace OpenTween { var shortUrl = new ShortUrl(http); - // http://t.co/hoge1 -> http://bit.ly/hoge2 + // https://t.co/hoge1 -> https://bit.ly/hoge2 handler.Enqueue(x => { Assert.Equal(HttpMethod.Head, x.Method); - Assert.Equal(new Uri("http://t.co/hoge1"), x.RequestUri); + Assert.Equal(new Uri("https://t.co/hoge1"), x.RequestUri); - return this.CreateRedirectResponse("http://bit.ly/hoge2"); + return this.CreateRedirectResponse("https://bit.ly/hoge2"); }); - // http://bit.ly/hoge2 -> http://tinyurl.com/hoge3 + // https://bit.ly/hoge2 -> https://tinyurl.com/hoge3 handler.Enqueue(x => { Assert.Equal(HttpMethod.Head, x.Method); - Assert.Equal(new Uri("http://bit.ly/hoge2"), x.RequestUri); + Assert.Equal(new Uri("https://bit.ly/hoge2"), x.RequestUri); - return this.CreateRedirectResponse("http://tinyurl.com/hoge3"); + return this.CreateRedirectResponse("https://tinyurl.com/hoge3"); }); - // http://tinyurl.com/hoge3 -> http://example.com/hoge4 + // https://tinyurl.com/hoge3 -> http://example.com/hoge4 handler.Enqueue(x => { // このリクエストは実行されないはず @@ -174,14 +174,64 @@ namespace OpenTween return this.CreateRedirectResponse("http://example.com/hoge4"); }); - Assert.Equal(new Uri("http://tinyurl.com/hoge3"), - await shortUrl.ExpandUrlAsync(new Uri("http://t.co/hoge1"), redirectLimit: 2)); + Assert.Equal(new Uri("https://tinyurl.com/hoge3"), + await shortUrl.ExpandUrlAsync(new Uri("https://t.co/hoge1"), redirectLimit: 2)); Assert.Equal(1, handler.QueueCount); } } [Fact] + public async Task ExpandUrlAsync_UpgradeToHttpsTest() + { + var handler = new HttpMessageHandlerMock(); + using (var http = new HttpClient(handler)) + { + var shortUrl = new ShortUrl(http); + + // http://t.co/hoge -> http://example.com/hoge + handler.Enqueue(x => + { + // https:// に変換されてリクエストが送信される + Assert.Equal(HttpMethod.Head, x.Method); + Assert.Equal(new Uri("https://t.co/hoge"), x.RequestUri); + + return this.CreateRedirectResponse("http://example.com/hoge"); + }); + + Assert.Equal(new Uri("http://example.com/hoge"), + await shortUrl.ExpandUrlAsync(new Uri("http://t.co/hoge"))); + + Assert.Equal(0, handler.QueueCount); + } + } + + [Fact] + public async Task ExpandUrlAsync_InsecureDomainTest() + { + var handler = new HttpMessageHandlerMock(); + using (var http = new HttpClient(handler)) + { + var shortUrl = new ShortUrl(http); + + // http://htn.to/hoge -> http://example.com/hoge + handler.Enqueue(x => + { + // HTTPS非対応のドメインは http:// のままリクエストが送信される + Assert.Equal(HttpMethod.Head, x.Method); + Assert.Equal(new Uri("http://htn.to/hoge"), x.RequestUri); + + return this.CreateRedirectResponse("http://example.com/hoge"); + }); + + Assert.Equal(new Uri("http://example.com/hoge"), + await shortUrl.ExpandUrlAsync(new Uri("http://htn.to/hoge"))); + + Assert.Equal(0, handler.QueueCount); + } + } + + [Fact] public async Task ExpandUrlAsync_RelativeUriTest() { var handler = new HttpMessageHandlerMock(); @@ -246,17 +296,17 @@ namespace OpenTween { var shortUrl = new ShortUrl(http); - // http://t.co/hoge1 -> http://example.com/hoge2 + // https://t.co/hoge1 -> http://example.com/hoge2 handler.Enqueue(x => { Assert.Equal(HttpMethod.Head, x.Method); - Assert.Equal(new Uri("http://t.co/hoge1"), x.RequestUri); + Assert.Equal(new Uri("https://t.co/hoge1"), x.RequestUri); return this.CreateRedirectResponse("http://example.com/hoge2"); }); Assert.Equal("http://example.com/hoge2", - await shortUrl.ExpandUrlAsync("http://t.co/hoge1")); + await shortUrl.ExpandUrlAsync("https://t.co/hoge1")); Assert.Equal(0, handler.QueueCount); } @@ -270,11 +320,11 @@ namespace OpenTween { var shortUrl = new ShortUrl(http); - // http://t.co/hoge1 -> http://example.com/hoge2 + // https://t.co/hoge1 -> http://example.com/hoge2 handler.Enqueue(x => { Assert.Equal(HttpMethod.Head, x.Method); - Assert.Equal(new Uri("http://t.co/hoge1"), x.RequestUri); + Assert.Equal(new Uri("https://t.co/hoge1"), x.RequestUri); return this.CreateRedirectResponse("http://example.com/hoge2"); }); @@ -317,14 +367,14 @@ namespace OpenTween { var shortUrl = new ShortUrl(http); - // http://t.co/hoge1 -> 503 Service Unavailable + // https://t.co/hoge1 -> 503 Service Unavailable handler.Enqueue(x => { return new HttpResponseMessage(HttpStatusCode.ServiceUnavailable); }); - Assert.Equal(new Uri("http://t.co/hoge1"), - await shortUrl.ExpandUrlAsync(new Uri("http://t.co/hoge1"))); + Assert.Equal(new Uri("https://t.co/hoge1"), + await shortUrl.ExpandUrlAsync(new Uri("https://t.co/hoge1"))); Assert.Equal(0, handler.QueueCount); } @@ -338,17 +388,17 @@ namespace OpenTween { var shortUrl = new ShortUrl(http); - // http://t.co/hoge1 -> http://example.com/hoge2 + // https://t.co/hoge1 -> http://example.com/hoge2 handler.Enqueue(x => { Assert.Equal(HttpMethod.Head, x.Method); - Assert.Equal(new Uri("http://t.co/hoge1"), x.RequestUri); + Assert.Equal(new Uri("https://t.co/hoge1"), x.RequestUri); return this.CreateRedirectResponse("http://example.com/hoge2"); }); Assert.Equal("hogehoge", - await shortUrl.ExpandUrlHtmlAsync("hogehoge")); + await shortUrl.ExpandUrlHtmlAsync("hogehoge")); Assert.Equal(0, handler.QueueCount); } diff --git a/OpenTween/Resources/ChangeLog.txt b/OpenTween/Resources/ChangeLog.txt index 137015f3..5fe0817b 100644 --- a/OpenTween/Resources/ChangeLog.txt +++ b/OpenTween/Resources/ChangeLog.txt @@ -5,6 +5,7 @@ - 対象となるショートカットは Ctrl+Alt+S (Fav+RT), Ctrl+Alt+R (Fav+非公式RT), Ctrl+Alt+H (ユーザー指定のURLを開く) の3つです * CHG: Microsoft Translator Text API v3 に対応 - OpenTweenの古いバージョンの翻訳機能は 2019/4/30 以降に使用できなくなります + * CHG: 短縮URLの展開時にHTTPSが使用できるドメインは強制的にHTTPSを使用する * CHG: 廃止された短縮URLサービスのドメインをURL展開の対象から削除 * CHG: 廃止された twurl.nl によるURL短縮機能を削除 * CHG: img.azyobuzi.net 利用時の接続先をHTTPSに変更 diff --git a/OpenTween/ShortUrl.cs b/OpenTween/ShortUrl.cs index 1a8255c2..2edf8c5a 100644 --- a/OpenTween/ShortUrl.cs +++ b/OpenTween/ShortUrl.cs @@ -117,6 +117,23 @@ namespace OpenTween "youtu.be", }; + /// + /// HTTPS非対応の短縮URLサービス + /// + private static readonly HashSet InsecureDomains = new HashSet + { + "budurl.com", + "ff.im", + "ht.ly", + "htn.to", + "moi.st", + "ow.ly", + "tinami.jp", + "tl.gd", + "twme.jp", + "urx2.nu", + }; + static ShortUrl() => _instance = new Lazy(() => new ShortUrl(), true); @@ -443,6 +460,8 @@ namespace OpenTween private async Task GetRedirectTo(Uri url) { + url = this.UpgradeToHttpsIfAvailable(url); + var request = new HttpRequestMessage(HttpMethod.Head, url); using (var response = await this.http.SendAsync(request).ConfigureAwait(false)) @@ -472,6 +491,24 @@ namespace OpenTween } } + /// + /// 指定されたURLのスキームを https:// に書き換える + /// + private Uri UpgradeToHttpsIfAvailable(Uri original) + { + if (original.Scheme != "http") + return original; + + if (InsecureDomains.Contains(original.Host)) + return original; + + var builder = new UriBuilder(original); + builder.Scheme = "https"; + builder.Port = 443; + + return builder.Uri; + } + [SuppressMessage("Microsoft.Reliability", "CA2000:DisposeObjectsBeforeLosingScope")] private static HttpClient CreateDefaultHttpClient() { -- 2.11.0