Skip to content

Commit bf6199e

Browse files
Merge pull request #20 from DaisukeDaisuke/newlogin
ミラティブの仕様変更に対応+新ログイン機構実装
2 parents d78a2d9 + af1a000 commit bf6199e

File tree

18 files changed

+784
-50
lines changed

18 files changed

+784
-50
lines changed

BrowserCookieImplementations/BrowserCookieImplementations.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@
3838
<ItemGroup>
3939
<PackageReference Include="BouncyCastle" Version="1.8.9" />
4040
<PackageReference Include="System.Data.SQLite.Core" Version="1.0.114.3" />
41+
<PackageReference Include="System.Security.Cryptography.ProtectedData" Version="9.0.8" />
42+
<PackageReference Include="System.Text.Json" Version="9.0.8" />
4143
</ItemGroup>
4244
<ItemGroup>
4345
<ProjectReference Include="..\BrowserCookieInterfaces\BrowserCookieInterfaces.csproj" />
Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Diagnostics;
4+
using System.IO;
5+
using System.Linq;
6+
using System.Net;
7+
using System.Security.Cryptography;
8+
using System.Text;
9+
using System.Text.Json;
10+
11+
namespace ryu_s.BrowserCookie
12+
{
13+
public class BuildinManager : IBrowserManager
14+
{
15+
public BrowserType Type => BrowserType.Buildin; // 新しいBrowserTypeが必要
16+
17+
public List<IBrowserProfile> GetProfiles()
18+
{
19+
var profiles = new List<IBrowserProfile>();
20+
profiles.Add(new BuildinProfile("default"));
21+
return profiles;
22+
}
23+
}
24+
25+
public class BuildinProfile : IBrowserProfile
26+
{
27+
public string Path { get; }
28+
public string ProfileName { get; }
29+
public BrowserType Type => BrowserType.Buildin;
30+
31+
public BuildinProfile(string profileName)
32+
{
33+
ProfileName = profileName ?? "default";
34+
Path = GetCookieFilePath(ProfileName);
35+
}
36+
37+
public Cookie GetCookie(string domain, string name)
38+
{
39+
var cookies = GetCookieCollection(domain);
40+
return cookies.FirstOrDefault(c => c.Name.Equals(name, StringComparison.OrdinalIgnoreCase));
41+
}
42+
43+
public List<Cookie> GetCookieCollection(string domain)
44+
{
45+
46+
Console.WriteLine($"Loading cookies for domain: {domain} from {Path}");
47+
48+
string fileName = domain switch
49+
{
50+
"mirrativ.com" => "Mirrativ.bin",
51+
"www.mirrativ.com" => "Mirrativ.bin",
52+
"youtube.com" => "YouTubeLive.bin",
53+
null => "unknown",
54+
_ => "unknown" // これがあると安全です
55+
};
56+
57+
var allCookies = LoadAllCookies(fileName);
58+
var result = new List<Cookie>();
59+
60+
foreach (var cookie in allCookies) {
61+
// ドメインマッチングロジック
62+
if (IsHostMatch(cookie.Domain, domain))
63+
{
64+
result.Add(cookie);
65+
}
66+
Debug.WriteLine(cookie.Domain);
67+
}
68+
return result;
69+
}
70+
71+
private List<Cookie> LoadAllCookies(string file)
72+
{
73+
var cookieList = new List<Cookie>();
74+
75+
var path1 = System.IO.Path.Combine(Path, file);
76+
77+
if (!File.Exists(path1))
78+
{
79+
return cookieList;
80+
}
81+
82+
try
83+
{
84+
// 暗号化されたファイルを読み込み
85+
var encrypted = File.ReadAllBytes(path1);
86+
87+
// DPAPI で復号
88+
var bytes = ProtectedData.Unprotect(encrypted, optionalEntropy: null, scope: DataProtectionScope.LocalMachine);
89+
var json = Encoding.UTF8.GetString(bytes);
90+
91+
// JSON を CookieDto のリストにデシリアライズ
92+
var cookieDtos = JsonSerializer.Deserialize<List<CookieDto>>(json);
93+
94+
if (cookieDtos != null)
95+
{
96+
foreach (var dto in cookieDtos)
97+
{
98+
try
99+
{
100+
var cookie = new Cookie(dto.Name, dto.Value, dto.Path ?? "/", dto.Domain ?? "");
101+
102+
// 有効期限を設定
103+
if (dto.Expires.HasValue)
104+
{
105+
cookie.Expires = dto.Expires.Value;
106+
}
107+
108+
// その他のプロパティを設定
109+
cookie.HttpOnly = dto.IsHttpOnly;
110+
cookie.Secure = dto.IsSecure;
111+
112+
cookieList.Add(cookie);
113+
}
114+
catch (Exception)
115+
{
116+
// 無効なクッキーは無視して続行
117+
}
118+
}
119+
}
120+
}
121+
catch (Exception)
122+
{
123+
// 復号化エラーまたはJSONパースエラーの場合は空のリストを返す
124+
}
125+
126+
return cookieList;
127+
}
128+
129+
private bool IsHostMatch(string cookieDomain, string requestDomain)
130+
{
131+
if (string.IsNullOrEmpty(cookieDomain) || string.IsNullOrEmpty(requestDomain))
132+
{
133+
return false;
134+
}
135+
136+
// 完全一致
137+
if (cookieDomain.Equals(requestDomain, StringComparison.OrdinalIgnoreCase))
138+
{
139+
return true;
140+
}
141+
142+
// ドット付きドメイン(.example.com)の場合、サブドメインマッチング
143+
if (cookieDomain.StartsWith("."))
144+
{
145+
var domain = cookieDomain.Substring(1);
146+
return requestDomain.Equals(domain, StringComparison.OrdinalIgnoreCase) ||
147+
requestDomain.EndsWith("." + domain, StringComparison.OrdinalIgnoreCase);
148+
}
149+
150+
// 逆パターン:requestDomainがサブドメインの場合
151+
if (requestDomain.Contains(cookieDomain))
152+
{
153+
return requestDomain.EndsWith("." + cookieDomain, StringComparison.OrdinalIgnoreCase) ||
154+
requestDomain.Equals(cookieDomain, StringComparison.OrdinalIgnoreCase);
155+
}
156+
157+
if (!cookieDomain.StartsWith(".") && cookieDomain.EndsWith(requestDomain))
158+
{
159+
return true;
160+
}
161+
162+
return false;
163+
}
164+
165+
private string GetCookieFilePath(string siteName)
166+
{
167+
var exeDir = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location)
168+
?? AppDomain.CurrentDomain.BaseDirectory;
169+
var folder = System.IO.Path.Combine(exeDir, "Cookies");
170+
Directory.CreateDirectory(folder);
171+
return folder;
172+
}
173+
}
174+
175+
// CookieDto クラス(CookieStorage.cs から移動または重複定義)
176+
public class CookieDto
177+
{
178+
public string Name { get; set; }
179+
public string Value { get; set; }
180+
public string Domain { get; set; }
181+
public string Path { get; set; }
182+
public DateTime? Expires { get; set; } // null = session cookie
183+
public bool IsHttpOnly { get; set; }
184+
public bool IsSecure { get; set; }
185+
}
186+
}

BrowserCookieInterfaces/BrowserType.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ public enum BrowserType
99
Edge,
1010
Opera,
1111
OperaGx,
12+
Buildin,
1213
Unknown,
1314
}
1415
}

CommentViewerCommon/BrowserLoader.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ public IEnumerable<IBrowserProfile> LoadBrowsers()
2323
new EdgeManager(),
2424
new OperaManager(),
2525
new OperaGxManager(),
26+
new BuildinManager(),
2627
};
2728
foreach (var manager in managers)
2829
{

MirrativSitePlugin/Api.cs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,18 +31,18 @@ public static async Task<CurrentUser> GetCurrentUserAsync(IDataServer server, Co
3131
}
3232
return currentUser;
3333
}
34-
public static async Task<ILiveInfo> PollLiveAsync(IDataServer server, string liveId)
34+
public static async Task<ILiveInfo> PollLiveAsync(IDataServer server, string liveId, CookieContainer cc)
3535
{
3636
//https://www.mirrativ.com/api/live/live_polling?live_id=qnLD1dkSheKqylMKKD5hOA
3737
var url = "https://www.mirrativ.com/api/live/live_polling?live_id=" + liveId;
38-
var res = await server.GetAsync(url, null);
38+
var res = await server.GetAsync(url, null, cc);
3939
var obj = Tools.Deserialize<Low.LiveInfo.RootObject>(res);
4040
return new LiveInfo(obj);
4141
}
42-
public static async Task<List<Message>> GetLiveComments(IDataServer server, string liveId)
42+
public static async Task<List<Message>> GetLiveComments(IDataServer server, string liveId, CookieContainer cc)
4343
{
4444
var url = "https://www.mirrativ.com/api/live/live_comments?live_id=" + liveId;
45-
var res = await server.GetAsync(url, null);
45+
var res = await server.GetAsync(url, null, cc);
4646
var obj = Tools.Deserialize<Low.LiveComments.RootObject>(res);
4747
var list = new List<Message>();
4848
foreach(var c in obj.Comments)
@@ -61,21 +61,21 @@ public static async Task<List<Message>> GetLiveComments(IDataServer server, stri
6161
list.Reverse();
6262
return list;
6363
}
64-
public static async Task<ILiveInfo> GetLiveInfo(IDataServer server, string liveId)
64+
public static async Task<ILiveInfo> GetLiveInfo(IDataServer server, string liveId, CookieContainer cc)
6565
{
6666
if (string.IsNullOrEmpty(liveId))
6767
{
6868
throw new ArgumentNullException(nameof(liveId));
6969
}
7070
var url = "https://www.mirrativ.com/api/live/live?live_id=" + liveId;
71-
var res = await server.GetAsync(url, null);
71+
var res = await server.GetAsync(url, null, cc);
7272
var obj = Tools.Deserialize<Low.LiveInfo.RootObject>(res);
7373
return new LiveInfo(obj);
7474
}
75-
public static async Task<UserProfile> GetUserProfileAsync(IDataServer server, string userId)
75+
public static async Task<UserProfile> GetUserProfileAsync(IDataServer server, string userId, CookieContainer cc)
7676
{
7777
var url = "https://www.mirrativ.com/api/user/profile?user_id=" + userId;
78-
var res = await server.GetAsync(url, null);
78+
var res = await server.GetAsync(url, null, cc);
7979
var obj = Tools.Deserialize<Low.UserProfile.RootObject>(res);
8080
return new UserProfile(obj);
8181
}

MirrativSitePlugin/DummyImpl.cs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
using System.Collections.Generic;
33
using System.Threading.Tasks;
44
using SitePluginCommon.AutoReconnection;
5+
using System.Net;
6+
using System.Diagnostics;
57

68
namespace MirrativSitePlugin
79
{
@@ -13,6 +15,8 @@ class DummyImpl : IDummy
1315
private readonly IMirrativSiteOptions _siteOptions;
1416
private readonly MessageProvider2 _p1;
1517
private readonly MetadataProvider2 _p2;
18+
private readonly CookieContainer _cc;
19+
1620

1721
public async Task<bool> CanConnectAsync()
1822
{
@@ -24,7 +28,7 @@ public async Task<bool> CanConnectAsync()
2428
else if (Tools.IsValidLiveId(input))
2529
{
2630
var liveId = Tools.ExtractLiveId(input);
27-
var liveInfo = await Api.GetLiveInfo(_server, liveId);
31+
var liveInfo = await Api.GetLiveInfo(_server, liveId, _cc);
2832
return liveInfo.IsLive;
2933
}
3034
else
@@ -57,8 +61,9 @@ public async Task<IEnumerable<IProvider>> GenerateGroupAsync()
5761
//エラーメッセージ
5862
return new List<IProvider>();
5963
}
60-
var liveInfo = await Api.GetLiveInfo(_server, liveId);
64+
var liveInfo = await Api.GetLiveInfo(_server, liveId, _cc);
6165
var broadcastKey = liveInfo.BcsvrKey;
66+
//Debug.WriteLine(broadcastKey);
6267
//var p1 = new MessageProvider2(new WebSocket("wss://online.mirrativ.com/"), _logger);
6368
//p1.MessageReceived += P1_MessageReceived;
6469
//p1.MetadataUpdated += P1_MetadataUpdated;
@@ -77,7 +82,7 @@ public async Task<IEnumerable<IProvider>> GenerateGroupAsync()
7782

7883
private async Task<string> GetLiveIdAsync(string userId)
7984
{
80-
var userProfile = await Api.GetUserProfileAsync(_server, userId);
85+
var userProfile = await Api.GetUserProfileAsync(_server, userId, _cc);
8186
if (!string.IsNullOrEmpty(userProfile.OnLiveLiveId))
8287
{
8388
return userProfile.OnLiveLiveId;
@@ -87,14 +92,15 @@ private async Task<string> GetLiveIdAsync(string userId)
8792
return null;
8893
}
8994
}
90-
public DummyImpl(IDataServer server, string input, ILogger logger, IMirrativSiteOptions siteOptions, MessageProvider2 p1, MetadataProvider2 p2)
95+
public DummyImpl(IDataServer server, string input, ILogger logger, IMirrativSiteOptions siteOptions, MessageProvider2 p1, MetadataProvider2 p2, CookieContainer cc)
9196
{
9297
_server = server;
9398
_input = input;
9499
_logger = logger;
95100
_siteOptions = siteOptions;
96101
_p1 = p1;
97102
_p2 = p2;
103+
_cc = cc;
98104
}
99105
}
100106
}

MirrativSitePlugin/MessageProvider.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.Collections.Generic;
33
using System.Diagnostics;
4+
using System.Net;
45
using System.Threading.Tasks;
56
using Common;
67
using SitePlugin;
@@ -193,6 +194,7 @@ class MessageProvider2 : IProvider
193194

194195
private readonly IWebSocket _webSocket;
195196
private readonly ILogger _logger;
197+
private readonly CookieContainer _cc;
196198
public string BroadcastKey { get; set; }
197199

198200
public event EventHandler<IMirrativMessage> MessageReceived;
@@ -207,10 +209,11 @@ public void Stop()
207209
{
208210
_webSocket.Disconnect();
209211
}
210-
public MessageProvider2(IWebSocket webSocket, ILogger logger)
212+
public MessageProvider2(IWebSocket webSocket, ILogger logger, CookieContainer cc)
211213
{
212214
_webSocket = webSocket;
213215
_logger = logger;
216+
_cc = cc;
214217
webSocket.Opened += WebSocket_Opened;
215218
webSocket.Received += WebSocket_Received;
216219
}

MirrativSitePlugin/MetadataProvider2.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using SitePluginCommon.AutoReconnection;
22
using System;
3+
using System.Net;
34
using System.Threading;
45
using System.Threading.Tasks;
56

@@ -18,6 +19,7 @@ class MetadataProvider2 : IProvider
1819
public Task Work { get; private set; }
1920
public ProviderFinishReason FinishReason { get; private set; }
2021
public string LiveId { get; set; }
22+
public CookieContainer _cc { get; set; }
2123
public void Start()
2224
{
2325
Work = ReceiveAsync();
@@ -43,7 +45,7 @@ private async Task ReceiveAsync()
4345

4446
protected virtual async Task<ILiveInfo> GetLiveInfoAsync()
4547
{
46-
return await Api.PollLiveAsync(_server, LiveId);
48+
return await Api.PollLiveAsync(_server, LiveId, _cc);
4749
}
4850

4951
protected virtual async Task Wait()
@@ -60,10 +62,11 @@ public void Stop()
6062
_isDisconnectRequested = true;
6163
_cts?.Cancel();
6264
}
63-
public MetadataProvider2(IDataServer server, IMirrativSiteOptions siteOptions)
65+
public MetadataProvider2(IDataServer server, IMirrativSiteOptions siteOptions, CookieContainer cc)
6466
{
6567
_server = server;
6668
_siteOptions = siteOptions;
69+
_cc = cc;
6770
}
6871
}
6972
}

0 commit comments

Comments
 (0)