diff --git a/TVTComment/Model/ChatCollectService/NiconicoLiveChatCollectService.cs b/TVTComment/Model/ChatCollectService/NiconicoLiveChatCollectService.cs index ed78816..dca9fac 100644 --- a/TVTComment/Model/ChatCollectService/NiconicoLiveChatCollectService.cs +++ b/TVTComment/Model/ChatCollectService/NiconicoLiveChatCollectService.cs @@ -48,6 +48,7 @@ protected ChatReceivingException( private readonly NiconicoUtils.NicoLiveCommentSender commentSender; private DateTime lastHeartbeatTime = DateTime.MinValue; private readonly CancellationTokenSource cancel = new CancellationTokenSource(); + private NiconicoUtils.NiconicoLoginSession session; public NiconicoLiveChatCollectService( ChatCollectServiceEntry.IChatCollectServiceEntry serviceEntry, string liveId, @@ -56,6 +57,7 @@ NiconicoUtils.NiconicoLoginSession session { this.ServiceEntry = serviceEntry; this.originalLiveId = liveId; + this.session = session; var assembly = Assembly.GetExecutingAssembly().GetName(); var ua = assembly.Name + "/" + assembly.Version.ToString(3); @@ -131,6 +133,8 @@ private async Task collectChat(CancellationToken cancel) } catch (HttpRequestException e) { + if (e.StatusCode == System.Net.HttpStatusCode.Unauthorized) + this.session.BadSession = true; throw new ChatReceivingException("サーバーとの通信でエラーが発生しました", e); } var playerStatus = await JsonDocument.ParseAsync(playerStatusStr, cancellationToken: cancel).ConfigureAwait(false); diff --git a/TVTComment/Model/ChatService/NiconicoChatService.cs b/TVTComment/Model/ChatService/NiconicoChatService.cs index 83b33ac..ea06ecd 100644 --- a/TVTComment/Model/ChatService/NiconicoChatService.cs +++ b/TVTComment/Model/ChatService/NiconicoChatService.cs @@ -10,6 +10,10 @@ class NiconicoChatServiceSettings { public string UserId { get; set; } = ""; public string Password { get; set; } = ""; + // ログインセッションを保持する + public string NicoSid { get; set; } = ""; + public string Session { get; set; } = ""; + public string SessionSecure { get; set; } = ""; } class NiconicoChatService : IChatService @@ -35,6 +39,18 @@ public string UserPassword get { return this.settings.Password; } } public bool IsLoggedin { get; private set; } + public string NicoSid + { + get { return this.settings.NicoSid; } + } + public string Session + { + get { return this.settings.Session; } + } + public string SessionSecure + { + get { return this.settings.SessionSecure; } + } public NiconicoChatService( NiconicoChatServiceSettings settings, ChannelDatabase channelDatabase, @@ -48,7 +64,7 @@ public NiconicoChatService( try { if(!string.IsNullOrWhiteSpace(UserId) && !string.IsNullOrWhiteSpace(UserPassword)) - SetUser(UserId, UserPassword).Wait(); + SetUser(UserId, UserPassword, NicoSid, Session, SessionSecure).Wait(); } catch (AggregateException e) when (e.InnerExceptions.Count == 1 && e.InnerExceptions[0] is NiconicoUtils.NiconicoLoginSessionException) @@ -68,9 +84,12 @@ public NiconicoChatService( /// /// ニコニコのユーザーID /// ニコニコのパスワード + /// ログインセッション(nicosid) + /// ログインセッション(user_session) + /// ログインセッション(user_session_secure) /// またはがnull若しくはホワイトスペースだった時 /// ログインに失敗した時 - public async Task SetUser(string userId, string userPassword) + public async Task SetUser(string userId, string userPassword, string nicoSid, string session, string sessionSecure) { if (string.IsNullOrWhiteSpace(userId)) throw new ArgumentException($"{nameof(userId)} must not be null nor white space", nameof(userId)); @@ -78,13 +97,16 @@ public async Task SetUser(string userId, string userPassword) throw new ArgumentException($"{nameof(userPassword)} must not be null nor white space", nameof(userPassword)); //ログインしてみる - var tmpSession = new NiconicoUtils.NiconicoLoginSession(userId, userPassword); + var tmpSession = new NiconicoUtils.NiconicoLoginSession(userId, userPassword, nicoSid, session, sessionSecure); await tmpSession.Login().ConfigureAwait(false); //成功したら設定、セッションを置き換える this.IsLoggedin = true; this.settings.UserId = userId; this.settings.Password = userPassword; + this.settings.NicoSid = tmpSession.nicosid; + this.settings.Session = tmpSession.session; + this.settings.SessionSecure = tmpSession.secure; try { await (this.loginSession.Value?.Logout() ?? Task.CompletedTask); diff --git a/TVTComment/Model/NiconicoUtils/NiconicoLoginSession.cs b/TVTComment/Model/NiconicoUtils/NiconicoLoginSession.cs index 1145b94..51fffb7 100644 --- a/TVTComment/Model/NiconicoUtils/NiconicoLoginSession.cs +++ b/TVTComment/Model/NiconicoUtils/NiconicoLoginSession.cs @@ -42,8 +42,12 @@ class NiconicoLoginSession { private string mail; private string password; + public string nicosid { get; private set; } + public string session { get; private set; } + public string secure { get; private set; } private CookieCollection cookie = null; + public bool BadSession = false; public bool IsLoggedin => cookie != null; /// /// 送信するべき認証情報を含んだクッキー @@ -60,10 +64,13 @@ public CookieCollection Cookie } } - public NiconicoLoginSession(string mail, string password) + public NiconicoLoginSession(string mail, string password, string nicosid, string session, string secure) { this.mail = mail; this.password = password; + this.nicosid = nicosid; + this.session = session; + this.secure = secure; } /// @@ -74,9 +81,20 @@ public NiconicoLoginSession(string mail, string password) /// public async Task Login() { - if (this.IsLoggedin) + if (!this.BadSession && this.IsLoggedin) throw new InvalidOperationException("すでにログインしています"); + if (!this.BadSession && nicosid != null && nicosid.Length > 0 && session != null && session.Length > 0 && secure != null && secure.Length > 0) + { + this.cookie = new CookieCollection(); + + this.cookie.Add(new Cookie("nicosid", nicosid, "/", "nicovideo.jp")); + this.cookie.Add(new Cookie("user_session", session, "/", "nicovideo.jp")); + this.cookie.Add(new Cookie("user_session_secure", secure, "/", "nicovideo.jp")); + + return; + } + const string loginUrl = "https://secure.nicovideo.jp/secure/login?site=niconico"; var handler = new HttpClientHandler(); @@ -102,6 +120,16 @@ public async Task Login() if (cookieCollection.All(x => x.Name != "user_session")) throw new LoginFailureNiconicoLoginSessionException(); + Cookie cookieNicosid = cookieCollection.Where(x => x.Name == "nicosid").Single(); + Cookie cookieSession = cookieCollection.Where(x => x.Name == "user_session").Single(); + Cookie cookieSecure = cookieCollection.Where(x => x.Name == "user_session_secure").Single(); + + this.nicosid = cookieNicosid.Value; + this.session = cookieSession.Value; + this.secure = cookieSecure.Value; + + this.BadSession = false; + this.cookie = cookieCollection; } @@ -128,6 +156,9 @@ public async Task Logout() throw new NetworkNiconicoLoginSessionException(e); } this.cookie = null; + this.nicosid = null; + this.session = null; + this.secure = null; } } } diff --git a/TVTComment/ViewModels/SettingsWindowViewModel.cs b/TVTComment/ViewModels/SettingsWindowViewModel.cs index 79d3b64..48641cb 100644 --- a/TVTComment/ViewModels/SettingsWindowViewModel.cs +++ b/TVTComment/ViewModels/SettingsWindowViewModel.cs @@ -15,6 +15,9 @@ class SettingsWindowViewModel : BindableBase public ObservableValue NiconicoLoginStatus { get; } = new ObservableValue(); public ObservableValue NiconicoUserId { get; } = new ObservableValue(); public ObservableValue NiconicoPassword { get; } = new ObservableValue(); + public ObservableValue NiconicoSid { get; } = new ObservableValue(); + public ObservableValue NiconicoSession { get; } = new ObservableValue(); + public ObservableValue NiconicoSecure { get; } = new ObservableValue(); public ObservableValue NichanResCollectInterval { get; } = new ObservableValue(); public ObservableValue NichanThreadSearchInterval { get; } = new ObservableValue(); public ObservableValue NichanApiHmKey { get; } = new ObservableValue(); @@ -52,7 +55,7 @@ public SettingsWindowViewModel(Model.TVTComment model) try { - await niconico.SetUser(NiconicoUserId.Value, NiconicoPassword.Value); + await niconico.SetUser(NiconicoUserId.Value, NiconicoPassword.Value, NiconicoSid.Value, NiconicoSession.Value, NiconicoSecure.Value); syncNiconicoUserStatus(); } catch (Model.NiconicoUtils.NiconicoLoginSessionException) @@ -97,6 +100,9 @@ private void syncNiconicoUserStatus() NiconicoLoginStatus.Value = niconico.IsLoggedin ? "ログイン済" : "未ログイン"; NiconicoUserId.Value = niconico.UserId; NiconicoPassword.Value = niconico.UserPassword; + NiconicoSid.Value = niconico.NicoSid; + NiconicoSession.Value = niconico.Session; + NiconicoSecure.Value = niconico.SessionSecure; } private void syncNichanSettings()