public override void Login(string password, bool rememberSession) { if (password == null) { throw new ArgumentNullException("password"); } // todo: remember sessions MainForm.SetSignInStatus("Connecting to ClassiCube.net..."); // download the login page string loginPage = DownloadString(LoginUri, ClassiCubeNet); Debug.WriteLine(loginPage); // See if we're already logged in if (LoggedInAs.IsMatch(loginPage)) { // todo } Match csrfTokenMatch = CsrfToken.Match(loginPage); if (!csrfTokenMatch.Success) { // todo: handle ClassiCube derping } string csrfToken = csrfTokenMatch.Groups[1].Value; string loginString = String.Format("csrf_token={0}&username={1}&password={2}", Uri.EscapeDataString(csrfToken), Uri.EscapeDataString(LoginUsername), Uri.EscapeDataString(password)); if (rememberSession) { loginString += "&remember_me=y"; } string loginResponse = UploadString(LoginUri, LoginUri, loginString); // See if now we're logged in if (loginResponse.Contains(LoginFailedMessage)) { Status = LoginResult.WrongUsernameOrPass; } else if (LoggedInAs.IsMatch(loginResponse)) { MinecraftUsername = LoggedInAs.Match(loginResponse).Groups[1].Value; // todo: get play session ID Status = LoginResult.Success; // todo: save cookie } else { MainForm.Log("CC.Login: Something went wrong: " + loginResponse); Status = LoginResult.UnrecognizedResponse; } }
// Takes AES-256 encrypted, base-64 encoded password. Returns true if decryption succeeded. public static string DecryptPassword(string encryptedString) { if (encryptedString == null) { throw new ArgumentNullException("encryptedString"); } try { byte[] bytesToDecrypt = Convert.FromBase64String(encryptedString); // extract the prepended IV, and byte[] vector = new byte[IVSize]; Buffer.BlockCopy(bytesToDecrypt, 0, vector, 0, IVSize); ICryptoTransform transform = Cipher.CreateDecryptor(Key, vector); // decrypt the data MemoryStream stream = new MemoryStream(); using (CryptoStream cs = new CryptoStream(stream, transform, CryptoStreamMode.Write)) { cs.Write(bytesToDecrypt, IVSize, bytesToDecrypt.Length - IVSize); } byte[] decryptedBytes = stream.ToArray(); // extract password from decrypted data string decryptedPassword = Encoding.UTF8.GetString(stream.ToArray(), ChecksumSize, decryptedBytes.Length - ChecksumSize); // calculate expected/actual checksums ushort expectedChecksum = BitConverter.ToUInt16(decryptedBytes, 0); ushort actualChecksum = ComputeChecksum(decryptedBytes, ChecksumSize, decryptedBytes.Length - ChecksumSize); if (expectedChecksum == actualChecksum) { // checksums match, all good return(decryptedPassword); } else { MainForm.Log("DecryptPassword: Decryption did not succeed; prefix mismatch."); } } catch (Exception ex) { MainForm.Log("DecryptPassword: Error while decrypting: " + ex); } return(""); }
// Handle saved minecraft.net sessions bool LoadCookie(bool remember) { if (File.Exists(Paths.CookieContainerFile)) { if (remember) { // load a saved session BinaryFormatter formatter = new BinaryFormatter(); using (Stream s = File.OpenRead(Paths.CookieContainerFile)) { CookieJar = (CookieContainer)formatter.Deserialize(s); } CookieCollection cookies = CookieJar.GetCookies(new Uri(MinecraftNet)); foreach (Cookie c in cookies) { // look for a cookie that corresponds to the current minecraft username int start = c.Value.IndexOf("username%3A" + MinecraftUsername, StringComparison.OrdinalIgnoreCase); if (start != -1) { MainForm.Log("MC.LoadCookie: Loaded saved session for " + MinecraftUsername); return(true); } } // if saved session was not for the current username, discard it MainForm.Log("MC.LoadCookie: Discarded a saved session (username mismatch)"); ResetCookies(); } else { // discard a saved session MainForm.Log("MC.LoadCookie: Discarded a saved session"); ResetCookies(); } } else { // no session saved ResetCookies(); } return(false); }
public void LoadAccounts() { storedAccounts.Clear(); string[] fileNames = Directory.GetFiles(Paths.DataDirectory, "*.account"); foreach (string fileName in fileNames) { try { SettingsFile sf = new SettingsFile(); sf.Load(fileName); SignInAccount newAccount = new SignInAccount { SignInUsername = sf.GetString("SignInUsername", ""), PlayerName = sf.GetString("PlayerName", ""), Password = sf.GetString("Password", ""), LastUrl = sf.GetString("LastUrl", "") }; if (newAccount.Password.Length > 0) { newAccount.Password = PasswordSecurity.DecryptPassword(newAccount.Password); } string tickString = sf.GetString("SignInDate", "0"); long ticks; if (Int64.TryParse(tickString, out ticks) && ticks > DateTime.MinValue.Ticks && ticks <= DateTime.MaxValue.Ticks) { newAccount.SignInDate = new DateTime(ticks); } else { newAccount.SignInDate = DateTime.MinValue; } AddAccount(newAccount); } catch (Exception ex) { MainForm.Log("AccountManager.LoadAccounts: " + ex); } } SaveAllAccounts(); }
public override void Login(string password, bool rememberSession) { if (password == null) { throw new ArgumentNullException("password"); } bool restoredSession = LoadCookie(rememberSession); MainForm.SetSignInStatus("Connecting to Minecraft.net..."); // check if cancel is needed if (cancel) { Status = LoginResult.Canceled; cancel = false; return; } // download the login page string loginPage = DownloadString(LoginSecureUri, MinecraftNet); // See if we're already logged in if (LoggedInAs.IsMatch(loginPage)) { string loggedInUsername = LoggedInAs.Match(loginPage).Groups[1].Value; if (rememberSession && PlaySessionCookie != null && MinecraftUsername.Equals(loggedInUsername, StringComparison.OrdinalIgnoreCase)) { // If player is already logged in with the right account: reuse a previous session MinecraftUsername = loggedInUsername; MainForm.Log("MC.Login: Restored session for " + MinecraftUsername); Status = LoginResult.Success; SaveCookie(); return; } else { // If we're not supposed to reuse session, if old username is different, // or if there is no play session cookie set - relog MainForm.SetSignInStatus("Switching accounts..."); DownloadString(LogoutUri, MinecraftNet); loginPage = DownloadString(LoginSecureUri, LogoutUri); } } // Extract authenticityToken from the login page Match authTokenMatch = LoginAuthToken.Match(loginPage); if (!authTokenMatch.Success) { if (restoredSession) { // restoring session failed; log out and retry DownloadString(LogoutUri, MinecraftNet); ResetCookies(); MainForm.Log("MC.Login: Unrecognized page; retrying"); Login(password, rememberSession); return; } else { // something unexpected happened, panic! MainForm.Log("MC.Login: Unrecognized page: " + loginPage); Status = LoginResult.UnrecognizedResponse; } return; } string authToken = authTokenMatch.Groups[1].Value; // Build up form data string loginString = String.Format("username={0}&password={1}&authenticityToken={2}", Uri.EscapeDataString(LoginUsername), Uri.EscapeDataString(password), Uri.EscapeDataString(authToken)); if (rememberSession) { loginString += "&remember=true"; } // check if cancel is needed if (cancel) { Status = LoginResult.Canceled; cancel = false; return; } // POST to the login form MainForm.SetSignInStatus("Sending login information..."); string loginResponse = UploadString(LoginSecureUri, LoginSecureUri, loginString); // check if cancel is needed if (cancel) { Status = LoginResult.Canceled; cancel = false; return; } // Check the response if (loginResponse.Contains(WrongUsernameOrPasswordMessage)) { Status = LoginResult.WrongUsernameOrPass; } else if (LoggedInAs.IsMatch(loginResponse)) { MinecraftUsername = LoggedInAs.Match(loginResponse).Groups[1].Value; if (PlaySessionCookie == null) { CookieCollection cookies = CookieJar.GetCookies(new Uri(MinecraftNet)); MainForm.Log("MC.Login: No play session. There were " + cookies.Count + " cookies served:"); foreach (Cookie cookie in cookies) { MainForm.Log(" " + cookie); } Status = LoginResult.NoPlaySession; return; } Status = LoginResult.Success; SaveCookie(); } else if (loginResponse.Contains(MigratedAccountMessage)) { Status = LoginResult.MigratedAccount; } else { MainForm.Log("MC.Login: Unrecognized response: " + loginResponse); Status = LoginResult.UnrecognizedResponse; } }