Files
ArchiSteamFarm/SteamAuth/UserLogin.cs
2016-03-10 21:11:54 +01:00

253 lines
9.1 KiB
C#

using Newtonsoft.Json;
using System;
using System.Collections.Specialized;
using System.Net;
using System.Security.Cryptography;
using System.Text;
namespace SteamAuth
{
/// <summary>
/// Handles logging the user into the mobile Steam website. Necessary to generate OAuth token and session cookies.
/// </summary>
public class UserLogin
{
public string Username;
public string Password;
public ulong SteamID;
public bool RequiresCaptcha;
public string CaptchaGID = null;
public string CaptchaText = null;
public bool RequiresEmail;
public string EmailDomain = null;
public string EmailCode = null;
public bool Requires2FA;
public string TwoFactorCode = null;
public SessionData Session = null;
public bool LoggedIn = false;
private CookieContainer _cookies = new CookieContainer();
public UserLogin(string username, string password)
{
this.Username = username;
this.Password = password;
}
public LoginResult DoLogin()
{
var postData = new NameValueCollection();
var cookies = _cookies;
string response = null;
if (cookies.Count == 0)
{
//Generate a SessionID
cookies.Add(new Cookie("mobileClientVersion", "0 (2.1.3)", "/", ".steamcommunity.com"));
cookies.Add(new Cookie("mobileClient", "android", "/", ".steamcommunity.com"));
cookies.Add(new Cookie("Steam_Language", "english", "/", ".steamcommunity.com"));
NameValueCollection headers = new NameValueCollection();
headers.Add("X-Requested-With", "com.valvesoftware.android.steam.community");
SteamWeb.MobileLoginRequest("https://steamcommunity.com/login?oauth_client_id=DE45CD61&oauth_scope=read_profile%20write_profile%20read_client%20write_client", "GET", null, cookies, headers);
}
postData.Add("username", this.Username);
response = SteamWeb.MobileLoginRequest(APIEndpoints.COMMUNITY_BASE + "/login/getrsakey", "POST", postData, cookies);
if (response == null || response.Contains("<BODY>\nAn error occurred while processing your request.")) return LoginResult.GeneralFailure;
var rsaResponse = JsonConvert.DeserializeObject<RSAResponse>(response);
if (!rsaResponse.Success)
{
return LoginResult.BadRSA;
}
RNGCryptoServiceProvider secureRandom = new RNGCryptoServiceProvider();
byte[] encryptedPasswordBytes;
using (var rsaEncryptor = new RSACryptoServiceProvider())
{
var passwordBytes = Encoding.ASCII.GetBytes(this.Password);
var rsaParameters = rsaEncryptor.ExportParameters(false);
rsaParameters.Exponent = Util.HexStringToByteArray(rsaResponse.Exponent);
rsaParameters.Modulus = Util.HexStringToByteArray(rsaResponse.Modulus);
rsaEncryptor.ImportParameters(rsaParameters);
encryptedPasswordBytes = rsaEncryptor.Encrypt(passwordBytes, false);
}
string encryptedPassword = Convert.ToBase64String(encryptedPasswordBytes);
postData.Clear();
postData.Add("username", this.Username);
postData.Add("password", encryptedPassword);
postData.Add("twofactorcode", this.TwoFactorCode ?? "");
postData.Add("captchagid", this.RequiresCaptcha ? this.CaptchaGID : "-1");
postData.Add("captcha_text", this.RequiresCaptcha ? this.CaptchaText : "");
postData.Add("emailsteamid", (this.Requires2FA || this.RequiresEmail) ? this.SteamID.ToString() : "");
postData.Add("emailauth", this.RequiresEmail ? this.EmailCode : "");
postData.Add("rsatimestamp", rsaResponse.Timestamp);
postData.Add("remember_login", "false");
postData.Add("oauth_client_id", "DE45CD61");
postData.Add("oauth_scope", "read_profile write_profile read_client write_client");
postData.Add("loginfriendlyname", "#login_emailauth_friendlyname_mobile");
postData.Add("donotcache", Util.GetSystemUnixTime().ToString());
response = SteamWeb.MobileLoginRequest(APIEndpoints.COMMUNITY_BASE + "/login/dologin", "POST", postData, cookies);
if (response == null) return LoginResult.GeneralFailure;
var loginResponse = JsonConvert.DeserializeObject<LoginResponse>(response);
if (loginResponse.Message != null && loginResponse.Message.Contains("Incorrect login"))
{
return LoginResult.BadCredentials;
}
if (loginResponse.CaptchaNeeded)
{
this.RequiresCaptcha = true;
this.CaptchaGID = loginResponse.CaptchaGID;
return LoginResult.NeedCaptcha;
}
if (loginResponse.EmailAuthNeeded)
{
this.RequiresEmail = true;
this.SteamID = loginResponse.EmailSteamID;
return LoginResult.NeedEmail;
}
if (loginResponse.TwoFactorNeeded && !loginResponse.Success)
{
this.Requires2FA = true;
return LoginResult.Need2FA;
}
if (loginResponse.Message != null && loginResponse.Message.Contains("too many login failures"))
{
return LoginResult.TooManyFailedLogins;
}
if (loginResponse.OAuthData == null || loginResponse.OAuthData.OAuthToken == null || loginResponse.OAuthData.OAuthToken.Length == 0)
{
return LoginResult.GeneralFailure;
}
if (!loginResponse.LoginComplete)
{
return LoginResult.BadCredentials;
}
else
{
var readableCookies = cookies.GetCookies(new Uri("https://steamcommunity.com"));
var oAuthData = loginResponse.OAuthData;
SessionData session = new SessionData();
session.OAuthToken = oAuthData.OAuthToken;
session.SteamID = oAuthData.SteamID;
session.SteamLogin = session.SteamID + "%7C%7C" + oAuthData.SteamLogin;
session.SteamLoginSecure = session.SteamID + "%7C%7C" + oAuthData.SteamLoginSecure;
session.WebCookie = oAuthData.Webcookie;
session.SessionID = readableCookies["sessionid"].Value;
this.Session = session;
this.LoggedIn = true;
return LoginResult.LoginOkay;
}
}
private class LoginResponse
{
[JsonProperty("success")]
public bool Success { get; set; }
[JsonProperty("login_complete")]
public bool LoginComplete { get; set; }
[JsonProperty("oauth")]
public string OAuthDataString { get; set; }
public OAuth OAuthData
{
get
{
return OAuthDataString != null ? JsonConvert.DeserializeObject<OAuth>(OAuthDataString) : null;
}
}
[JsonProperty("captcha_needed")]
public bool CaptchaNeeded { get; set; }
[JsonProperty("captcha_gid")]
public string CaptchaGID { get; set; }
[JsonProperty("emailsteamid")]
public ulong EmailSteamID { get; set; }
[JsonProperty("emailauth_needed")]
public bool EmailAuthNeeded { get; set; }
[JsonProperty("requires_twofactor")]
public bool TwoFactorNeeded { get; set; }
[JsonProperty("message")]
public string Message { get; set; }
internal class OAuth
{
[JsonProperty("steamid")]
public ulong SteamID { get; set; }
[JsonProperty("oauth_token")]
public string OAuthToken { get; set; }
[JsonProperty("wgtoken")]
public string SteamLogin { get; set; }
[JsonProperty("wgtoken_secure")]
public string SteamLoginSecure { get; set; }
[JsonProperty("webcookie")]
public string Webcookie { get; set; }
}
}
private class RSAResponse
{
[JsonProperty("success")]
public bool Success { get; set; }
[JsonProperty("publickey_exp")]
public string Exponent { get; set; }
[JsonProperty("publickey_mod")]
public string Modulus { get; set; }
[JsonProperty("timestamp")]
public string Timestamp { get; set; }
[JsonProperty("steamid")]
public ulong SteamID { get; set; }
}
}
public enum LoginResult
{
LoginOkay,
GeneralFailure,
BadRSA,
BadCredentials,
NeedCaptcha,
Need2FA,
NeedEmail,
TooManyFailedLogins,
}
}