-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #3 from AN0NCER/framework
Adding Library Framework 4.8
- Loading branch information
Showing
12 changed files
with
1,535 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
namespace SteamAuth | ||
{ | ||
public static class APIEndpoints | ||
{ | ||
public const string STEAMAPI_BASE = "https://api.steampowered.com"; | ||
public const string COMMUNITY_BASE = "https://steamcommunity.com"; | ||
public const string MOBILEAUTH_BASE = STEAMAPI_BASE + "/IMobileAuthService/%s/v0001"; | ||
public static string MOBILEAUTH_GETWGTOKEN = MOBILEAUTH_BASE.Replace("%s", "GetWGToken"); | ||
public const string TWO_FACTOR_BASE = STEAMAPI_BASE + "/ITwoFactorService/%s/v0001"; | ||
public static string TWO_FACTOR_TIME_QUERY = TWO_FACTOR_BASE.Replace("%s", "QueryTime"); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,288 @@ | ||
using Newtonsoft.Json; | ||
using System; | ||
using System.Collections.Specialized; | ||
using System.Net; | ||
using System.Security.Cryptography; | ||
using System.Threading; | ||
|
||
namespace SteamAuth | ||
{ | ||
/// <summary> | ||
/// Handles the linking process for a new mobile authenticator. | ||
/// </summary> | ||
public class AuthenticatorLinker | ||
{ | ||
/// <summary> | ||
/// Set to register a new phone number when linking. If a phone number is not set on the account, this must be set. If a phone number is set on the account, this must be null. | ||
/// </summary> | ||
public string PhoneNumber = null; | ||
|
||
/// <summary> | ||
/// Randomly-generated device ID. Should only be generated once per linker. | ||
/// </summary> | ||
public string DeviceID { get; private set; } | ||
|
||
/// <summary> | ||
/// After the initial link step, if successful, this will be the SteamGuard data for the account. PLEASE save this somewhere after generating it; it's vital data. | ||
/// </summary> | ||
public SteamGuardAccount LinkedAccount { get; private set; } | ||
|
||
/// <summary> | ||
/// True if the authenticator has been fully finalized. | ||
/// </summary> | ||
public bool Finalized = false; | ||
|
||
private SessionData _session; | ||
private CookieContainer _cookies; | ||
private bool confirmationEmailSent = false; | ||
|
||
public AuthenticatorLinker(SessionData session) | ||
{ | ||
this._session = session; | ||
this.DeviceID = GenerateDeviceID(); | ||
|
||
this._cookies = new CookieContainer(); | ||
session.AddCookies(_cookies); | ||
} | ||
|
||
public LinkResult AddAuthenticator() | ||
{ | ||
bool hasPhone = _hasPhoneAttached(); | ||
if (hasPhone && PhoneNumber != null) | ||
return LinkResult.MustRemovePhoneNumber; | ||
if (!hasPhone && PhoneNumber == null) | ||
return LinkResult.MustProvidePhoneNumber; | ||
|
||
if (!hasPhone) { | ||
if (confirmationEmailSent) { | ||
if (!_checkEmailConfirmation()) { | ||
return LinkResult.GeneralFailure; | ||
} | ||
} else if (!_addPhoneNumber()) { | ||
return LinkResult.GeneralFailure; | ||
} else { | ||
confirmationEmailSent = true; | ||
return LinkResult.MustConfirmEmail; | ||
} | ||
} | ||
|
||
var postData = new NameValueCollection(); | ||
postData.Add("access_token", _session.OAuthToken); | ||
postData.Add("steamid", _session.SteamID.ToString()); | ||
postData.Add("authenticator_type", "1"); | ||
postData.Add("device_identifier", this.DeviceID); | ||
postData.Add("sms_phone_id", "1"); | ||
|
||
string response = SteamWeb.MobileLoginRequest(APIEndpoints.STEAMAPI_BASE + "/ITwoFactorService/AddAuthenticator/v0001", "POST", postData); | ||
if (response == null) return LinkResult.GeneralFailure; | ||
|
||
var addAuthenticatorResponse = JsonConvert.DeserializeObject<AddAuthenticatorResponse>(response); | ||
if (addAuthenticatorResponse == null || addAuthenticatorResponse.Response == null) | ||
{ | ||
return LinkResult.GeneralFailure; | ||
} | ||
|
||
if (addAuthenticatorResponse.Response.Status == 29) | ||
{ | ||
return LinkResult.AuthenticatorPresent; | ||
} | ||
|
||
if (addAuthenticatorResponse.Response.Status != 1) | ||
{ | ||
return LinkResult.GeneralFailure; | ||
} | ||
|
||
this.LinkedAccount = addAuthenticatorResponse.Response; | ||
LinkedAccount.Session = this._session; | ||
LinkedAccount.DeviceID = this.DeviceID; | ||
|
||
return LinkResult.AwaitingFinalization; | ||
} | ||
|
||
public FinalizeResult FinalizeAddAuthenticator(string smsCode) | ||
{ | ||
//The act of checking the SMS code is necessary for Steam to finalize adding the phone number to the account. | ||
//Of course, we only want to check it if we're adding a phone number in the first place... | ||
|
||
if (!String.IsNullOrEmpty(this.PhoneNumber) && !this._checkSMSCode(smsCode)) | ||
{ | ||
return FinalizeResult.BadSMSCode; | ||
} | ||
|
||
var postData = new NameValueCollection(); | ||
postData.Add("steamid", _session.SteamID.ToString()); | ||
postData.Add("access_token", _session.OAuthToken); | ||
postData.Add("activation_code", smsCode); | ||
int tries = 0; | ||
while (tries <= 30) | ||
{ | ||
postData.Set("authenticator_code", LinkedAccount.GenerateSteamGuardCode()); | ||
postData.Set("authenticator_time", TimeAligner.GetSteamTime().ToString()); | ||
|
||
string response = SteamWeb.MobileLoginRequest(APIEndpoints.STEAMAPI_BASE + "/ITwoFactorService/FinalizeAddAuthenticator/v0001", "POST", postData); | ||
if (response == null) return FinalizeResult.GeneralFailure; | ||
|
||
var finalizeResponse = JsonConvert.DeserializeObject<FinalizeAuthenticatorResponse>(response); | ||
|
||
if (finalizeResponse == null || finalizeResponse.Response == null) | ||
{ | ||
return FinalizeResult.GeneralFailure; | ||
} | ||
|
||
if (finalizeResponse.Response.Status == 89) | ||
{ | ||
return FinalizeResult.BadSMSCode; | ||
} | ||
|
||
if (finalizeResponse.Response.Status == 88) | ||
{ | ||
if (tries >= 30) | ||
{ | ||
return FinalizeResult.UnableToGenerateCorrectCodes; | ||
} | ||
} | ||
|
||
if (!finalizeResponse.Response.Success) | ||
{ | ||
return FinalizeResult.GeneralFailure; | ||
} | ||
|
||
if (finalizeResponse.Response.WantMore) | ||
{ | ||
tries++; | ||
continue; | ||
} | ||
|
||
this.LinkedAccount.FullyEnrolled = true; | ||
return FinalizeResult.Success; | ||
} | ||
|
||
return FinalizeResult.GeneralFailure; | ||
} | ||
|
||
private bool _checkSMSCode(string smsCode) | ||
{ | ||
var postData = new NameValueCollection(); | ||
postData.Add("op", "check_sms_code"); | ||
postData.Add("arg", smsCode); | ||
postData.Add("checkfortos", "0"); | ||
postData.Add("skipvoip", "1"); | ||
postData.Add("sessionid", _session.SessionID); | ||
|
||
string response = SteamWeb.Request(APIEndpoints.COMMUNITY_BASE + "/steamguard/phoneajax", "POST", postData, _cookies); | ||
if (response == null) return false; | ||
|
||
var addPhoneNumberResponse = JsonConvert.DeserializeObject<AddPhoneResponse>(response); | ||
|
||
if (!addPhoneNumberResponse.Success) | ||
{ | ||
Thread.Sleep(3500); //It seems that Steam needs a few seconds to finalize the phone number on the account. | ||
return _hasPhoneAttached(); | ||
} | ||
|
||
return true; | ||
} | ||
|
||
private bool _addPhoneNumber() | ||
{ | ||
var postData = new NameValueCollection(); | ||
postData.Add("op", "add_phone_number"); | ||
postData.Add("arg", PhoneNumber); | ||
postData.Add("sessionid", _session.SessionID); | ||
|
||
string response = SteamWeb.Request(APIEndpoints.COMMUNITY_BASE + "/steamguard/phoneajax", "POST", postData, _cookies); | ||
if (response == null) return false; | ||
|
||
var addPhoneNumberResponse = JsonConvert.DeserializeObject<AddPhoneResponse>(response); | ||
return addPhoneNumberResponse.Success; | ||
} | ||
|
||
private bool _checkEmailConfirmation() { | ||
var postData = new NameValueCollection(); | ||
postData.Add("op", "email_confirmation"); | ||
postData.Add("arg", ""); | ||
postData.Add("sessionid", _session.SessionID); | ||
|
||
string response = SteamWeb.Request(APIEndpoints.COMMUNITY_BASE + "/steamguard/phoneajax", "POST", postData, _cookies); | ||
if (response == null) return false; | ||
|
||
var emailConfirmationResponse = JsonConvert.DeserializeObject<AddPhoneResponse>(response); | ||
return emailConfirmationResponse.Success; | ||
} | ||
|
||
private bool _hasPhoneAttached() { | ||
var postData = new NameValueCollection(); | ||
postData.Add("op", "has_phone"); | ||
postData.Add("arg", "null"); | ||
postData.Add("sessionid", _session.SessionID); | ||
|
||
string response = SteamWeb.Request(APIEndpoints.COMMUNITY_BASE + "/steamguard/phoneajax", "POST", postData, _cookies); | ||
if (response == null) return false; | ||
|
||
var hasPhoneResponse = JsonConvert.DeserializeObject<HasPhoneResponse>(response); | ||
return hasPhoneResponse.HasPhone; | ||
} | ||
|
||
public enum LinkResult | ||
{ | ||
MustProvidePhoneNumber, //No phone number on the account | ||
MustRemovePhoneNumber, //A phone number is already on the account | ||
MustConfirmEmail, //User need to click link from confirmation email | ||
AwaitingFinalization, //Must provide an SMS code | ||
GeneralFailure, //General failure (really now!) | ||
AuthenticatorPresent | ||
} | ||
|
||
public enum FinalizeResult | ||
{ | ||
BadSMSCode, | ||
UnableToGenerateCorrectCodes, | ||
Success, | ||
GeneralFailure | ||
} | ||
|
||
private class AddAuthenticatorResponse | ||
{ | ||
[JsonProperty("response")] | ||
public SteamGuardAccount Response { get; set; } | ||
} | ||
|
||
private class FinalizeAuthenticatorResponse | ||
{ | ||
[JsonProperty("response")] | ||
public FinalizeAuthenticatorInternalResponse Response { get; set; } | ||
|
||
internal class FinalizeAuthenticatorInternalResponse | ||
{ | ||
[JsonProperty("status")] | ||
public int Status { get; set; } | ||
|
||
[JsonProperty("server_time")] | ||
public long ServerTime { get; set; } | ||
|
||
[JsonProperty("want_more")] | ||
public bool WantMore { get; set; } | ||
|
||
[JsonProperty("success")] | ||
public bool Success { get; set; } | ||
} | ||
} | ||
|
||
private class HasPhoneResponse | ||
{ | ||
[JsonProperty("has_phone")] | ||
public bool HasPhone { get; set; } | ||
} | ||
|
||
private class AddPhoneResponse | ||
{ | ||
[JsonProperty("success")] | ||
public bool Success { get; set; } | ||
} | ||
|
||
public static string GenerateDeviceID() | ||
{ | ||
return "android:" + Guid.NewGuid().ToString(); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
|
||
namespace SteamAuth | ||
{ | ||
public class Confirmation | ||
{ | ||
/// <summary> | ||
/// The ID of this confirmation | ||
/// </summary> | ||
public ulong ID; | ||
|
||
/// <summary> | ||
/// The unique key used to act upon this confirmation. | ||
/// </summary> | ||
public ulong Key; | ||
|
||
/// <summary> | ||
/// The value of the data-type HTML attribute returned for this contribution. | ||
/// </summary> | ||
public int IntType; | ||
|
||
/// <summary> | ||
/// Represents either the Trade Offer ID or market transaction ID that caused this confirmation to be created. | ||
/// </summary> | ||
public ulong Creator; | ||
|
||
/// <summary> | ||
/// The type of this confirmation. | ||
/// </summary> | ||
public ConfirmationType ConfType; | ||
|
||
public Confirmation(ulong id, ulong key, int type, ulong creator) | ||
{ | ||
this.ID = id; | ||
this.Key = key; | ||
this.IntType = type; | ||
this.Creator = creator; | ||
|
||
//Do a switch simply because we're not 100% certain of all the possible types. | ||
switch (type) | ||
{ | ||
case 1: | ||
this.ConfType = ConfirmationType.GenericConfirmation; | ||
break; | ||
case 2: | ||
this.ConfType = ConfirmationType.Trade; | ||
break; | ||
case 3: | ||
this.ConfType = ConfirmationType.MarketSellTransaction; | ||
break; | ||
default: | ||
this.ConfType = ConfirmationType.Unknown; | ||
break; | ||
} | ||
} | ||
|
||
public enum ConfirmationType | ||
{ | ||
GenericConfirmation, | ||
Trade, | ||
MarketSellTransaction, | ||
Unknown | ||
} | ||
} | ||
} |
Oops, something went wrong.