/// <summary> /// /// </summary> /// <returns></returns> public async Task <AccessToken> GetAccessToken() { AccessToken accessToken; PtcLoginParameters loginData = null; var cookies = Cookies.GetCookies("sso.pokemon.com").ToList(); // @robertmclaws: "CASTGC" is the name of the login cookie that the service looks for, afaik. // The second one is listed as a backup in case they change the cookie name. if (!cookies.Any(c => c.Name == "CASTGC") || cookies.Count == 0) { loginData = await GetLoginParameters().ConfigureAwait(false); } var authTicket = await GetAuthenticationTicket(loginData).ConfigureAwait(false); accessToken = await GetOAuthToken(authTicket).ConfigureAwait(false); return(accessToken); }
/// <summary> /// Authenticates against the PTC login service and acquires an Authentication Ticket. /// </summary> /// <param name="httpClient">The <see cref="HttpClient"/> instance to use for this request.</param> /// <param name="loginData">The <see cref="PtcLoginParameters" /> to use from this request. Obtained by calling <see cref="GetLoginParameters(HttpClient)"/>.</param> /// <returns></returns> private async Task <string> GetAuthenticationTicket(PtcLoginParameters loginData) { var requestData = new Dictionary <string, string> { { "lt", loginData.Lt }, { "execution", loginData.Execution }, { "_eventId", "submit" }, { "username", Username }, { "password", Password } }; var responseMessage = await HttpClient.PostAsync(Constants.LoginUrl, new FormUrlEncodedContent(requestData)).ConfigureAwait(false); // robertmclaws: No need to even read the string if we have results from the location query. if (responseMessage.Headers.Location != null) { var decoder = new WwwFormUrlDecoder(responseMessage.Headers.Location.Query); if (decoder.Count == 0) { if (Debugger.IsAttached) { Debugger.Break(); } throw new LoginFailedException(); } return(decoder.GetFirstValueByName("ticket")); } var responseContent = await responseMessage.Content.ReadAsStringAsync().ConfigureAwait(false); var response = JsonConvert.DeserializeObject <PtcAuthenticationTicketResponse>(responseContent); var loginFailedWords = new string[] { "incorrect", "disabled" }; var loginFailed = loginFailedWords.Any(failedWord => response.Errors.Any(error => error.Contains(failedWord))); if (loginFailed) { throw new LoginFailedException(responseMessage); } throw new Exception($"Pokemon Trainer Club responded with the following error(s): '{string.Join(", ", response.Errors)}'"); }
/// <summary> /// Authenticates against the PTC login service and acquires an Authentication Ticket. /// </summary> /// <param name="loginData">The <see cref="PtcLoginParameters" /> to use from this request. Obtained by calling <see cref="GetLoginParameters(HttpClient)"/>.</param> /// <returns></returns> private async Task <string> GetAuthenticationTicket(PtcLoginParameters loginData) { HttpResponseMessage responseMessage; if (loginData != null) { var requestData = new Dictionary <string, string> { { "lt", loginData.Lt }, { "execution", loginData.Execution }, { "_eventId", "submit" }, { "username", Username }, { "password", Password } }; responseMessage = await HttpClient.PostAsync(Constants.LoginUrl, new FormUrlEncodedContent(requestData)).ConfigureAwait(false); } else { responseMessage = await HttpClient.GetAsync(Constants.LoginUrl); } // robertmclaws: No need to even read the string if we have results from the location query. if (responseMessage.StatusCode == HttpStatusCode.Found && responseMessage.Headers.Location != null) { var decoder = new WwwFormUrlDecoder(responseMessage.Headers.Location.Query); if (decoder.Count == 0) { if (Debugger.IsAttached) { Debugger.Break(); } throw new LoginFailedException(); } return(decoder.GetFirstValueByName("ticket")); } var responseContent = await responseMessage.Content.ReadAsStringAsync().ConfigureAwait(false); PtcAuthenticationTicketResponse response = null; // @robertmclaws: Let's try to catch situations we haven't thought of yet. try { response = JsonConvert.DeserializeObject <PtcAuthenticationTicketResponse>(responseContent); } catch (Exception ex) { Logger.Write(ex.Message); throw new LoginFailedException("We encountered a response from the PTC login servers thet we didn't anticipate. Please take a screenshot and open a ticket." + Environment.NewLine + responseContent.Replace("/n", "")); } if (!string.IsNullOrWhiteSpace(response.ErrorCode) && response.ErrorCode.EndsWith("activation_required")) { throw new LoginFailedException($"Your two-day grace period has expired, and your PTC account must now be activated." + Environment.NewLine + $"Please visit {response.Redirect}."); } var loginFailedWords = new string[] { "incorrect", "disabled" }; var loginFailed = loginFailedWords.Any(failedWord => response.Errors.Any(error => error.Contains(failedWord))); if (loginFailed) { throw new LoginFailedException(response.Errors[0]); } throw new Exception($"Pokemon Trainer Club responded with the following error(s): '{string.Join(", ", response.Errors)}'"); }