Compare commits

...

70 Commits

Author SHA1 Message Date
JustArchi
d0d670f1a5 Add warning for invalid protocols 2016-03-19 11:48:51 +01:00
JustArchi
3597c8f138 Make it possible to run steam client with UDP 2016-03-19 11:33:39 +01:00
JustArchi
8a8ec29b41 Fix OnBotShutdown() firing too fast 2016-03-18 20:56:23 +01:00
JustArchi
a3352d032d Bump 2016-03-18 20:45:31 +01:00
JustArchi
d5f8647fcc Misc 2016-03-18 20:36:13 +01:00
JustArchi
79a700d786 Fix group chat commands, #165 2016-03-18 20:35:42 +01:00
JustArchi
bc223f0644 Misc 2016-03-18 14:54:42 +01:00
JustArchi
2b0d82453b Speedup login by doing independent tasks in parallel 2016-03-18 14:47:52 +01:00
JustArchi
fa0150e745 Code review 2016-03-18 14:39:59 +01:00
JustArchi
c95d11ef66 Actually do not respond to non-authorized users at all 2016-03-18 14:13:04 +01:00
JustArchi
63b268f9c4 Bump 2016-03-18 14:09:24 +01:00
JustArchi
03d38f8a2a Fix derp, #165 2016-03-18 14:05:18 +01:00
JustArchi
c88d9bf123 Implement SteamOwnerID 2016-03-18 09:02:09 +01:00
JustArchi
053ebe15bb Prepare for SteamOwnerID 2016-03-18 03:52:36 +01:00
JustArchi
b03bfb6bbc Don't touch old log when disabled 2016-03-18 03:48:00 +01:00
JustArchi
e48867000e Add LogToFile, closes #168 2016-03-18 03:45:59 +01:00
JustArchi
e08cdbd74d Bump 2016-03-16 19:58:21 +01:00
JustArchi
0b4c585a58 Bump 2016-03-16 19:55:16 +01:00
JustArchi
6213e77fab Time to sleep 2016-03-15 07:09:30 +01:00
JustArchi
fccca6a4fc Misc 2016-03-15 07:04:31 +01:00
JustArchi
d4f4ec3401 Misc 2016-03-15 05:16:22 +01:00
JustArchi
b23dd3612d Misc 2016-03-15 05:15:22 +01:00
JustArchi
ca4fa4ac27 Packages update 2016-03-15 05:03:50 +01:00
JustArchi
5e53a208d5 Misc 2016-03-15 04:51:51 +01:00
JustArchi
895c69642d Add !owns, closes #159 2016-03-15 04:20:28 +01:00
JustArchi
765f9d29bb Fix version comparison bug (and bump to 2.0.1.0 to fix legacy versions) 2016-03-14 22:40:19 +01:00
JustArchi
99af5c86a5 Bump 2016-03-14 22:20:06 +01:00
JustArchi
0bb2b3ed5f Add UnobservedTaskExceptionHandler, thank you @Netshroud 2016-03-14 20:51:29 +01:00
JustArchi
4181f3ba21 Add workaround for broken GenerateMachineID(), #154 2016-03-14 20:38:17 +01:00
JustArchi
c189b398c0 Improve readability 2016-03-14 18:24:03 +01:00
JustArchi
de4fbf8b04 Accept only trade confirmations when dealing with trades 2016-03-14 18:13:33 +01:00
JustArchi
f91a558314 Bump 2016-03-13 22:58:52 +01:00
JustArchi
7587ff024c Add more debugging for SK2 2016-03-13 21:22:52 +01:00
JustArchi
06778c9bb0 Misc 2016-03-13 20:56:23 +01:00
JustArchi
7a97045412 Add ForceHttp 2016-03-13 20:19:52 +01:00
JustArchi
5d9bedfd28 Misc 2016-03-13 18:16:43 +01:00
JustArchi
575992c25d Increase HttpTimeout to 60 2016-03-13 17:03:15 +01:00
JustArchi
72db5bc9f3 We don't need that delay anymore 2016-03-12 17:03:53 +01:00
JustArchi
b015720a3e Add workaround for Volvo fuckup, #135 2016-03-12 17:02:02 +01:00
JustArchi
84a6d4501b Bump 2016-03-12 06:39:08 +01:00
JustArchi
07049e71c0 Misc 2016-03-12 06:01:55 +01:00
JustArchi
4710d9c1eb Add support for WinAuth, #144 2016-03-12 05:58:51 +01:00
JustArchi
d08462745a I swear no more bumps tonight 2016-03-11 21:42:16 +01:00
JustArchi
eb4e9ee077 Fix remaining crash 2016-03-11 21:40:25 +01:00
JustArchi
601a486b13 Bump 2016-03-11 19:58:03 +01:00
JustArchi
14867f470d Derp 2016-03-11 19:49:52 +01:00
JustArchi
187f0800b2 Add !update 2016-03-11 19:48:14 +01:00
JustArchi
3afa202d0b Misc 2016-03-11 19:42:15 +01:00
JustArchi
d33e76c8b0 Add !farm, closes #151 2016-03-11 19:39:25 +01:00
JustArchi
3061c55eaf Bump 2016-03-11 19:15:56 +01:00
JustArchi
621a1dc2cb Do not crash on bad configs 2016-03-11 18:49:29 +01:00
JustArchi
1a832780a2 Bump 2016-03-11 18:35:42 +01:00
JustArchi
ab531c80df Misc 2016-03-11 02:15:25 +01:00
JustArchi
f20ea0a87f Add FarmingPeriod 2016-03-11 02:07:20 +01:00
JustArchi
3e7f726afb Bump 2016-03-11 00:52:15 +01:00
JustArchi
d247515a03 Confirmations should be minutes-based 2016-03-10 22:54:59 +01:00
JustArchi
f084a3f219 Mark inventory on login if needed 2016-03-10 21:44:45 +01:00
JustArchi
4d3673c305 Forgot to add 2016-03-10 21:19:21 +01:00
JustArchi
0253c3bf7b Add AcceptConfirmationsPeriod 2016-03-10 21:17:48 +01:00
JustArchi
0eae895676 SteamAuth update 2016-03-10 21:11:54 +01:00
JustArchi
045acb362d Code review 2016-03-10 02:21:28 +01:00
JustArchi
ebd65da3ff Misc 2016-03-10 01:23:32 +01:00
JustArchi
1de3c5bec0 Code review 2016-03-10 01:20:17 +01:00
JustArchi
b334c939df Add !2faok 2016-03-10 00:40:30 +01:00
JustArchi
8e6100e236 Add MaxFarmingTime, FarmingDelay 2016-03-09 19:25:45 +01:00
JustArchi
8cb512b6e5 Add InventoryLimiterDelay, rename RequestLimiterDelay to LoginLimiterDelay 2016-03-09 18:58:14 +01:00
JustArchi
6a28946205 Refresh farming queue when farming is finished 2016-03-09 18:50:54 +01:00
JustArchi
c632c025cb Move Statistics to global config 2016-03-09 05:02:07 +01:00
JustArchi
1403ffe190 This actually DOES work on Mono, hooray! 2016-03-09 03:52:43 +01:00
JustArchi
71ae9a84da Fix misc bug, #48 2016-03-09 03:52:04 +01:00
51 changed files with 1285 additions and 584 deletions

View File

@@ -265,6 +265,36 @@ namespace ArchiSteamFarm {
}
}
// TODO: Please remove me immediately after https://github.com/SteamRE/SteamKit/issues/254 gets fixed
internal void HackedLogOn(SteamUser.LogOnDetails details) {
if (!Client.IsConnected) {
return;
}
SteamID steamID = new SteamID(details.AccountID, details.AccountInstance, Client.ConnectedUniverse, EAccountType.Individual);
var logon = new ClientMsgProtobuf<CMsgClientLogon>(EMsg.ClientLogon);
logon.Body.obfustucated_private_ip = details.LoginID.Value;
logon.ProtoHeader.client_sessionid = 0;
logon.ProtoHeader.steamid = steamID.ConvertToUInt64();
logon.Body.account_name = details.Username;
logon.Body.password = details.Password;
logon.Body.should_remember_password = details.ShouldRememberPassword;
logon.Body.protocol_version = MsgClientLogon.CurrentProtocol;
logon.Body.client_os_type = (uint) details.ClientOSType;
logon.Body.client_language = details.ClientLanguage;
logon.Body.cell_id = details.CellID;
logon.Body.steam2_ticket_request = details.RequestSteam2Ticket;
logon.Body.client_package_version = 1771;
logon.Body.auth_code = details.AuthCode;
logon.Body.two_factor_code = details.TwoFactorCode;
logon.Body.login_key = details.LoginKey;
logon.Body.sha_sentryfile = details.SentryFileHash;
logon.Body.eresult_sentryfile = (int) (details.SentryFileHash != null ? EResult.OK : EResult.FileNotFound);
Client.Send(logon);
}
/*
_ _ _ _
| | | | __ _ _ __ __| || | ___ _ __ ___

View File

@@ -76,7 +76,7 @@
<Private>True</Private>
</Reference>
<Reference Include="Newtonsoft.Json, Version=8.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.8.0.2\lib\net45\Newtonsoft.Json.dll</HintPath>
<HintPath>..\packages\Newtonsoft.Json.8.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="protobuf-net, Version=2.0.0.668, Culture=neutral, PublicKeyToken=257b51d87d2e4d67, processorArchitecture=MSIL">
@@ -105,17 +105,14 @@
<Compile Include="GlobalDatabase.cs" />
<Compile Include="BotDatabase.cs" />
<Compile Include="CardsFarmer.cs" />
<Compile Include="CMsgClientClanInviteAction.cs" />
<Compile Include="CMsgs\CMsgClientClanInviteAction.cs" />
<Compile Include="Debugging.cs" />
<Compile Include="GlobalConfig.cs" />
<Compile Include="JSON\GitHub.cs" />
<Compile Include="JSON\Steam.cs" />
<Compile Include="Logging.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SteamItem.cs" />
<Compile Include="SteamItemList.cs" />
<Compile Include="SteamTradeOffer.cs" />
<Compile Include="SteamTradeOfferRequest.cs" />
<Compile Include="Trading.cs" />
<Compile Include="Utilities.cs" />
<Compile Include="WCF.cs" />

View File

@@ -31,9 +31,14 @@ using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
namespace ArchiSteamFarm {
internal sealed class ArchiWebHandler {
private const string SteamCommunity = "steamcommunity.com";
private static string SteamCommunityURL = "https://" + SteamCommunity;
private static int Timeout = 30 * 1000;
private readonly Bot Bot;
@@ -43,9 +48,14 @@ namespace ArchiSteamFarm {
internal static void Init() {
Timeout = Program.GlobalConfig.HttpTimeout * 1000;
SteamCommunityURL = (Program.GlobalConfig.ForceHttp ? "http://" : "https://") + SteamCommunity;
}
internal ArchiWebHandler(Bot bot) {
if (bot == null) {
return;
}
Bot = bot;
}
@@ -62,7 +72,7 @@ namespace ArchiSteamFarm {
byte[] sessionKey = CryptoHelper.GenerateRandomBlock(32);
// RSA encrypt it with the public key for the universe we're on
byte[] cryptedSessionKey = null;
byte[] cryptedSessionKey;
using (RSACrypto rsa = new RSACrypto(KeyDictionary.GetPublicKey(steamClient.ConnectedUniverse))) {
cryptedSessionKey = rsa.Encrypt(sessionKey);
}
@@ -87,7 +97,7 @@ namespace ArchiSteamFarm {
sessionkey: Encoding.ASCII.GetString(WebUtility.UrlEncodeToBytes(cryptedSessionKey, 0, cryptedSessionKey.Length)),
encrypted_loginkey: Encoding.ASCII.GetString(WebUtility.UrlEncodeToBytes(cryptedLoginKey, 0, cryptedLoginKey.Length)),
method: WebRequestMethods.Http.Post,
secure: true
secure: !Program.GlobalConfig.ForceHttp
);
} catch (Exception e) {
Logging.LogGenericException(e, Bot.BotName);
@@ -122,7 +132,7 @@ namespace ArchiSteamFarm {
HtmlDocument htmlDocument = null;
for (byte i = 0; i < WebBrowser.MaxRetries && htmlDocument == null; i++) {
htmlDocument = await WebBrowser.UrlGetToHtmlDocument("https://steamcommunity.com/my/profile", Cookie).ConfigureAwait(false);
htmlDocument = await WebBrowser.UrlGetToHtmlDocument(SteamCommunityURL + "/my/profile", Cookie).ConfigureAwait(false);
}
if (htmlDocument == null) {
@@ -145,7 +155,52 @@ namespace ArchiSteamFarm {
return false;
}
internal List<SteamTradeOffer> GetTradeOffers() {
internal async Task<Dictionary<uint, string>> GetOwnedGames() {
if (SteamID == 0) {
return null;
}
string request = SteamCommunityURL + "/profiles/" + SteamID + "/games/?xml=1";
XmlDocument response = null;
for (byte i = 0; i < WebBrowser.MaxRetries && response == null; i++) {
response = await WebBrowser.UrlGetToXML(request, Cookie).ConfigureAwait(false);
}
if (response == null) {
Logging.LogGenericWTF("Request failed even after " + WebBrowser.MaxRetries + " tries", Bot.BotName);
return null;
}
XmlNodeList xmlNodeList = response.SelectNodes("gamesList/games/game");
if (xmlNodeList == null || xmlNodeList.Count == 0) {
return null;
}
Dictionary<uint, string> result = new Dictionary<uint, string>(xmlNodeList.Count);
foreach (XmlNode xmlNode in xmlNodeList) {
XmlNode appNode = xmlNode.SelectSingleNode("appID");
if (appNode == null) {
continue;
}
uint appID;
if (!uint.TryParse(appNode.InnerText, out appID)) {
continue;
}
XmlNode nameNode = xmlNode.SelectSingleNode("name");
if (nameNode == null) {
continue;
}
result[appID] = nameNode.InnerText;
}
return result;
}
internal List<Steam.TradeOffer> GetTradeOffers() {
if (string.IsNullOrEmpty(Bot.BotConfig.SteamApiKey)) {
return null;
}
@@ -159,7 +214,7 @@ namespace ArchiSteamFarm {
response = iEconService.GetTradeOffers(
get_received_offers: 1,
active_only: 1,
secure: true
secure: !Program.GlobalConfig.ForceHttp
);
} catch (Exception e) {
Logging.LogGenericException(e, Bot.BotName);
@@ -172,15 +227,15 @@ namespace ArchiSteamFarm {
return null;
}
List<SteamTradeOffer> result = new List<SteamTradeOffer>();
List<Steam.TradeOffer> result = new List<Steam.TradeOffer>();
foreach (KeyValue trade in response["trade_offers_received"].Children) {
SteamTradeOffer tradeOffer = new SteamTradeOffer {
Steam.TradeOffer tradeOffer = new Steam.TradeOffer {
tradeofferid = trade["tradeofferid"].AsString(),
accountid_other = trade["accountid_other"].AsInteger(),
trade_offer_state = trade["trade_offer_state"].AsEnum<SteamTradeOffer.ETradeOfferState>()
accountid_other = (uint) trade["accountid_other"].AsUnsignedLong(), // TODO: Correct this when SK2 with https://github.com/SteamRE/SteamKit/pull/255 gets released
trade_offer_state = trade["trade_offer_state"].AsEnum<Steam.TradeOffer.ETradeOfferState>()
};
foreach (KeyValue item in trade["items_to_give"].Children) {
tradeOffer.items_to_give.Add(new SteamItem {
tradeOffer.items_to_give.Add(new Steam.Item {
appid = item["appid"].AsString(),
contextid = item["contextid"].AsString(),
assetid = item["assetid"].AsString(),
@@ -190,7 +245,7 @@ namespace ArchiSteamFarm {
});
}
foreach (KeyValue item in trade["items_to_receive"].Children) {
tradeOffer.items_to_receive.Add(new SteamItem {
tradeOffer.items_to_receive.Add(new Steam.Item {
appid = item["appid"].AsString(),
contextid = item["contextid"].AsString(),
assetid = item["assetid"].AsString(),
@@ -215,7 +270,7 @@ namespace ArchiSteamFarm {
return false;
}
string request = "https://steamcommunity.com/gid/" + clanID;
string request = SteamCommunityURL + "/gid/" + clanID;
Dictionary<string, string> data = new Dictionary<string, string>(2) {
{"sessionID", sessionID},
@@ -245,7 +300,7 @@ namespace ArchiSteamFarm {
return false;
}
string referer = "https://steamcommunity.com/tradeoffer/" + tradeID;
string referer = SteamCommunityURL + "/tradeoffer/" + tradeID;
string request = referer + "/accept";
Dictionary<string, string> data = new Dictionary<string, string>(3) {
@@ -281,7 +336,7 @@ namespace ArchiSteamFarm {
response = iEconService.DeclineTradeOffer(
tradeofferid: tradeID.ToString(),
method: WebRequestMethods.Http.Post,
secure: true
secure: !Program.GlobalConfig.ForceHttp
);
} catch (Exception e) {
Logging.LogGenericException(e, Bot.BotName);
@@ -297,10 +352,10 @@ namespace ArchiSteamFarm {
return true;
}
internal async Task<List<SteamItem>> GetMyTradableInventory() {
internal async Task<List<Steam.Item>> GetMyTradableInventory() {
JObject jObject = null;
for (byte i = 0; i < WebBrowser.MaxRetries && jObject == null; i++) {
jObject = await WebBrowser.UrlGetToJObject("https://steamcommunity.com/my/inventory/json/753/6?trading=1", Cookie).ConfigureAwait(false);
jObject = await WebBrowser.UrlGetToJObject(SteamCommunityURL + "/my/inventory/json/753/6?trading=1", Cookie).ConfigureAwait(false);
}
if (jObject == null) {
@@ -314,10 +369,10 @@ namespace ArchiSteamFarm {
return null;
}
List<SteamItem> result = new List<SteamItem>();
List<Steam.Item> result = new List<Steam.Item>();
foreach (JToken jToken in jTokens) {
try {
result.Add(JsonConvert.DeserializeObject<SteamItem>(jToken.ToString()));
result.Add(JsonConvert.DeserializeObject<Steam.Item>(jToken.ToString()));
} catch (Exception e) {
Logging.LogGenericException(e, Bot.BotName);
}
@@ -326,7 +381,7 @@ namespace ArchiSteamFarm {
return result;
}
internal async Task<bool> SendTradeOffer(List<SteamItem> inventory, ulong partnerID, string token = null) {
internal async Task<bool> SendTradeOffer(List<Steam.Item> inventory, ulong partnerID, string token = null) {
if (inventory == null || inventory.Count == 0 || partnerID == 0) {
return false;
}
@@ -336,21 +391,21 @@ namespace ArchiSteamFarm {
return false;
}
List<SteamTradeOfferRequest> trades = new List<SteamTradeOfferRequest>(1 + inventory.Count / Trading.MaxItemsPerTrade);
List<Steam.TradeOfferRequest> trades = new List<Steam.TradeOfferRequest>(1 + inventory.Count / Trading.MaxItemsPerTrade);
SteamTradeOfferRequest singleTrade = null;
Steam.TradeOfferRequest singleTrade = null;
for (ushort i = 0; i < inventory.Count; i++) {
if (i % Trading.MaxItemsPerTrade == 0) {
if (trades.Count >= Trading.MaxTradesPerAccount) {
break;
}
singleTrade = new SteamTradeOfferRequest();
singleTrade = new Steam.TradeOfferRequest();
trades.Add(singleTrade);
}
SteamItem item = inventory[i];
singleTrade.me.assets.Add(new SteamItem() {
Steam.Item item = inventory[i];
singleTrade.me.assets.Add(new Steam.Item() {
appid = "753",
contextid = "6",
amount = item.amount,
@@ -358,17 +413,17 @@ namespace ArchiSteamFarm {
});
}
string referer = "https://steamcommunity.com/tradeoffer/new";
string referer = SteamCommunityURL + "/tradeoffer/new";
string request = referer + "/send";
foreach (SteamTradeOfferRequest trade in trades) {
foreach (Steam.TradeOfferRequest trade in trades) {
Dictionary<string, string> data = new Dictionary<string, string>(6) {
{"sessionid", sessionID},
{"serverid", "1"},
{"partner", partnerID.ToString()},
{"tradeoffermessage", "Sent by ASF"},
{"json_tradeoffer", JsonConvert.SerializeObject(trade)},
{"trade_offer_create_params", string.IsNullOrEmpty(token) ? "" : string.Format("{{ \"trade_offer_access_token\":\"{0}\" }}", token)} // TODO: This should be rewrote
{"trade_offer_create_params", string.IsNullOrEmpty(token) ? "" : $"{{\"trade_offer_access_token\":\"{token}\"}}"}
};
HttpResponseMessage response = null;
@@ -392,7 +447,7 @@ namespace ArchiSteamFarm {
HtmlDocument htmlDocument = null;
for (byte i = 0; i < WebBrowser.MaxRetries && htmlDocument == null; i++) {
htmlDocument = await WebBrowser.UrlGetToHtmlDocument("https://steamcommunity.com/profiles/" + SteamID + "/badges?l=english&p=" + page, Cookie).ConfigureAwait(false);
htmlDocument = await WebBrowser.UrlGetToHtmlDocument(SteamCommunityURL + "/profiles/" + SteamID + "/badges?l=english&p=" + page, Cookie).ConfigureAwait(false);
}
if (htmlDocument == null) {
@@ -410,7 +465,7 @@ namespace ArchiSteamFarm {
HtmlDocument htmlDocument = null;
for (byte i = 0; i < WebBrowser.MaxRetries && htmlDocument == null; i++) {
htmlDocument = await WebBrowser.UrlGetToHtmlDocument("https://steamcommunity.com/profiles/" + SteamID + "/gamecards/" + appID + "?l=english", Cookie).ConfigureAwait(false);
htmlDocument = await WebBrowser.UrlGetToHtmlDocument(SteamCommunityURL + "/profiles/" + SteamID + "/gamecards/" + appID + "?l=english", Cookie).ConfigureAwait(false);
}
if (htmlDocument == null) {
@@ -428,7 +483,7 @@ namespace ArchiSteamFarm {
HttpResponseMessage response = null;
for (byte i = 0; i < WebBrowser.MaxRetries && response == null; i++) {
response = await WebBrowser.UrlGet("https://steamcommunity.com/profiles/" + SteamID + "/inventory", Cookie).ConfigureAwait(false);
response = await WebBrowser.UrlGet(SteamCommunityURL + "/profiles/" + SteamID + "/inventory", Cookie).ConfigureAwait(false);
}
if (response == null) {
@@ -449,9 +504,12 @@ namespace ArchiSteamFarm {
{ "pin", parentalPin }
};
string referer = SteamCommunityURL;
string request = referer + "/parental/ajaxunlock";
HttpResponseMessage response = null;
for (byte i = 0; i < WebBrowser.MaxRetries && response == null; i++) {
response = await WebBrowser.UrlPost("https://steamcommunity.com/parental/ajaxunlock", data, Cookie, "https://steamcommunity.com/").ConfigureAwait(false);
response = await WebBrowser.UrlPost(request, data, Cookie, referer).ConfigureAwait(false);
}
if (response == null) {
@@ -466,13 +524,20 @@ namespace ArchiSteamFarm {
}
foreach (string setCookieValue in setCookieValues) {
if (setCookieValue.Contains("steamparental=")) {
string setCookie = setCookieValue.Substring(setCookieValue.IndexOf("steamparental=") + 14);
setCookie = setCookie.Substring(0, setCookie.IndexOf(';'));
Cookie["steamparental"] = setCookie;
Logging.LogGenericInfo("Success!", Bot.BotName);
return;
if (!setCookieValue.Contains("steamparental=")) {
continue;
}
string setCookie = setCookieValue.Substring(setCookieValue.IndexOf("steamparental=", StringComparison.Ordinal) + 14);
int index = setCookie.IndexOf(';');
if (index > 0) {
setCookie = setCookie.Substring(0, index);
}
Cookie["steamparental"] = setCookie;
Logging.LogGenericInfo("Success!", Bot.BotName);
return;
}
Logging.LogGenericWarning("Failed to unlock parental account!", Bot.BotName);

File diff suppressed because it is too large Load Diff

View File

@@ -87,15 +87,15 @@ namespace ArchiSteamFarm {
[JsonProperty(Required = Required.DisallowNull)]
internal byte SendTradePeriod { get; private set; } = 0;
[JsonProperty(Required = Required.DisallowNull)]
internal byte AcceptConfirmationsPeriod { get; private set; } = 0;
[JsonProperty]
internal string CustomGamePlayedWhileIdle { get; private set; } = null;
[JsonProperty(Required = Required.DisallowNull)]
internal HashSet<uint> GamesPlayedWhileIdle { get; private set; } = new HashSet<uint>() { 0 };
[JsonProperty(Required = Required.DisallowNull)]
internal bool Statistics { get; private set; } = true;
internal static BotConfig Load(string path) {
if (!File.Exists(path)) {
@@ -200,8 +200,6 @@ namespace ArchiSteamFarm {
}
break;
case "Statistics":
botConfig.Statistics = bool.Parse(value);
break;
case "Blacklist":
case "SteamNickname":
break;

View File

@@ -57,10 +57,10 @@ namespace ArchiSteamFarm {
}
}
[JsonProperty(Required = Required.AllowNull)]
[JsonProperty]
private string _LoginKey;
[JsonProperty(Required = Required.AllowNull)]
[JsonProperty]
private SteamGuardAccount _SteamGuardAccount;
private string FilePath;
@@ -91,7 +91,7 @@ namespace ArchiSteamFarm {
// This constructor is used only by deserializer
private BotDatabase() { }
private void Save() {
internal void Save() {
lock (FilePath) {
try {
File.WriteAllText(FilePath, JsonConvert.SerializeObject(this));

View File

@@ -27,17 +27,15 @@ using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
namespace ArchiSteamFarm {
internal sealed class CardsFarmer {
private const byte StatusCheckSleep = 5; // In minutes, how long to wait before checking the appID again
private const ushort MaxFarmingTime = 600; // In minutes, how long ASF is allowed to farm one game in solo mode
internal readonly ConcurrentDictionary<uint, float> GamesToFarm = new ConcurrentDictionary<uint, float>();
internal readonly List<uint> CurrentGamesFarming = new List<uint>();
internal readonly HashSet<uint> CurrentGamesFarming = new HashSet<uint>();
private readonly ManualResetEvent FarmResetEvent = new ManualResetEvent(false);
private readonly SemaphoreSlim Semaphore = new SemaphoreSlim(1);
@@ -49,24 +47,28 @@ namespace ArchiSteamFarm {
private bool NowFarming = false;
internal CardsFarmer(Bot bot) {
if (bot == null) {
return;
}
Bot = bot;
if (Timer == null) {
if (Program.GlobalConfig.IdleFarmingPeriod > 0 && Timer == null) {
Timer = new Timer(
async e => await CheckGamesForFarming().ConfigureAwait(false),
null,
TimeSpan.FromMinutes(15), // Delay
TimeSpan.FromMinutes(60) // Period
TimeSpan.FromHours(Program.GlobalConfig.IdleFarmingPeriod), // Delay
TimeSpan.FromHours(Program.GlobalConfig.IdleFarmingPeriod) // Period
);
}
}
internal static List<uint> GetGamesToFarmSolo(ConcurrentDictionary<uint, float> gamesToFarm) {
internal static HashSet<uint> GetGamesToFarmSolo(ConcurrentDictionary<uint, float> gamesToFarm) {
if (gamesToFarm == null) {
return null;
}
List<uint> result = new List<uint>();
HashSet<uint> result = new HashSet<uint>();
foreach (KeyValuePair<uint, float> keyValue in gamesToFarm) {
if (keyValue.Value >= 2) {
result.Add(keyValue.Key);
@@ -81,11 +83,7 @@ namespace ArchiSteamFarm {
return 0;
}
foreach (uint appID in gamesToFarm.Keys) {
return appID;
}
return 0;
return gamesToFarm.Keys.FirstOrDefault();
}
internal async Task<bool> SwitchToManualMode(bool manualMode) {
@@ -112,7 +110,6 @@ namespace ArchiSteamFarm {
}
float maxHour = 0;
foreach (float hour in appIDs.Values) {
if (hour > maxHour) {
maxHour = hour;
@@ -170,6 +167,7 @@ namespace ArchiSteamFarm {
if (!await IsAnythingToFarm().ConfigureAwait(false)) {
Semaphore.Release(); // We have nothing to do, don't forget to release semaphore
Logging.LogGenericInfo("We don't have anything to farm on this account!", Bot.BotName);
return;
}
@@ -183,10 +181,10 @@ namespace ArchiSteamFarm {
if (Bot.BotConfig.CardDropsRestricted) { // If we have restricted card drops, we use complex algorithm
Logging.LogGenericInfo("Chosen farming algorithm: Complex", Bot.BotName);
while (GamesToFarm.Count > 0) {
List<uint> gamesToFarmSolo = GetGamesToFarmSolo(GamesToFarm);
HashSet<uint> gamesToFarmSolo = GetGamesToFarmSolo(GamesToFarm);
if (gamesToFarmSolo.Count > 0) {
while (gamesToFarmSolo.Count > 0) {
uint appID = gamesToFarmSolo[0];
uint appID = gamesToFarmSolo.First();
if (await FarmSolo(appID).ConfigureAwait(false)) {
farmedSomething = true;
Logging.LogGenericInfo("Done farming: " + appID, Bot.BotName);
@@ -199,7 +197,6 @@ namespace ArchiSteamFarm {
}
} else {
if (FarmMultiple(GamesToFarm)) {
farmedSomething = true;
Logging.LogGenericInfo("Done farming: " + string.Join(", ", GamesToFarm.Keys), Bot.BotName);
} else {
NowFarming = false;
@@ -224,6 +221,14 @@ namespace ArchiSteamFarm {
CurrentGamesFarming.Clear();
CurrentGamesFarming.TrimExcess();
NowFarming = false;
// We finished our queue for now, make sure that everything is indeed farmed before proceeding further
// Some games could be added in the meantime
if (await IsAnythingToFarm().ConfigureAwait(false)) {
Task.Run(async () => await StartFarming().ConfigureAwait(false)).Forget();
return;
}
Logging.LogGenericInfo("Farming finished!", Bot.BotName);
await Bot.OnFarmingFinished(farmedSomething).ConfigureAwait(false);
}
@@ -249,7 +254,7 @@ namespace ArchiSteamFarm {
private async Task<bool> IsAnythingToFarm() {
if (NowFarming) {
return false;
return true;
}
if (await Bot.ArchiWebHandler.ReconnectIfNeeded().ConfigureAwait(false)) {
@@ -292,12 +297,12 @@ namespace ArchiSteamFarm {
await Task.WhenAll(tasks).ConfigureAwait(false);
if (GamesToFarm.Count == 0) {
return true;
return false;
}
// If we have restricted card drops, actually do check hours of all games that are left to farm
if (Bot.BotConfig.CardDropsRestricted) {
tasks = new List<Task>(GamesToFarm.Keys.Count);
tasks = new List<Task>(GamesToFarm.Count);
Logging.LogGenericInfo("Checking hours...", Bot.BotName);
foreach (uint appID in GamesToFarm.Keys) {
tasks.Add(Task.Run(async () => await CheckHours(appID).ConfigureAwait(false)));
@@ -320,7 +325,7 @@ namespace ArchiSteamFarm {
foreach (HtmlNode htmlNode in htmlNodeCollection) {
string steamLink = htmlNode.GetAttributeValue("href", null);
if (steamLink == null) {
if (string.IsNullOrEmpty(steamLink)) {
continue;
}
@@ -387,14 +392,14 @@ namespace ArchiSteamFarm {
}
private async Task CheckGamesForFarming() {
if (NowFarming || ManualMode || GamesToFarm.Count > 0 || !Bot.SteamClient.IsConnected) {
if (NowFarming || ManualMode || !Bot.SteamClient.IsConnected) {
return;
}
await StartFarming().ConfigureAwait(false);
}
private async Task<bool?> ShouldFarm(ulong appID) {
private async Task<bool?> ShouldFarm(uint appID) {
if (appID == 0) {
return false;
}
@@ -419,13 +424,13 @@ namespace ArchiSteamFarm {
bool success = true;
bool? keepFarming = await ShouldFarm(appID).ConfigureAwait(false);
for (ushort farmingTime = 0; farmingTime <= MaxFarmingTime && (!keepFarming.HasValue || keepFarming.Value); farmingTime += StatusCheckSleep) {
Logging.LogGenericInfo("Still farming: " + appID, Bot.BotName);
if (FarmResetEvent.WaitOne(1000 * 60 * StatusCheckSleep)) {
for (ushort farmingTime = 0; farmingTime <= 60 * Program.GlobalConfig.MaxFarmingTime && keepFarming.GetValueOrDefault(true); farmingTime += Program.GlobalConfig.FarmingDelay) {
if (FarmResetEvent.WaitOne(60 * 1000 * Program.GlobalConfig.FarmingDelay)) {
success = false;
break;
}
keepFarming = await ShouldFarm(appID).ConfigureAwait(false);
Logging.LogGenericInfo("Still farming: " + appID, Bot.BotName);
}
Bot.ResetGamesPlayed();
@@ -443,13 +448,13 @@ namespace ArchiSteamFarm {
bool success = true;
while (maxHour < 2) {
Logging.LogGenericInfo("Still farming: " + string.Join(", ", appIDs), Bot.BotName);
if (FarmResetEvent.WaitOne(1000 * 60 * StatusCheckSleep)) {
if (FarmResetEvent.WaitOne(60 * 1000 * Program.GlobalConfig.FarmingDelay)) {
success = false;
break;
}
// Don't forget to update our GamesToFarm hours
float timePlayed = StatusCheckSleep / 60.0F;
float timePlayed = Program.GlobalConfig.FarmingDelay / 60.0F;
foreach (KeyValuePair<uint, float> gameToFarm in GamesToFarm) {
if (!appIDs.Contains(gameToFarm.Key)) {
continue;

View File

@@ -22,6 +22,10 @@
*/
using SteamKit2;
using System;
using System.IO;
namespace ArchiSteamFarm {
internal static class Debugging {
#if DEBUG
@@ -33,5 +37,27 @@ namespace ArchiSteamFarm {
internal static bool IsReleaseBuild => !IsDebugBuild;
internal static bool NetHookAlreadyInitialized { get; set; } = false;
internal sealed class DebugListener : IDebugListener {
private readonly string FilePath;
internal DebugListener(string filePath) {
if (string.IsNullOrEmpty(filePath)) {
return;
}
FilePath = filePath;
}
public void WriteLine(string category, string msg) {
lock (FilePath) {
try {
File.AppendAllText(FilePath, category + " | " + msg + Environment.NewLine);
} catch (Exception e) {
Logging.LogGenericException(e);
}
}
}
}
}
}

View File

@@ -26,6 +26,7 @@ using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Sockets;
namespace ArchiSteamFarm {
internal sealed class GlobalConfig {
@@ -45,16 +46,37 @@ namespace ArchiSteamFarm {
internal bool AutoUpdates { get; private set; } = true;
[JsonProperty(Required = Required.DisallowNull)]
internal EUpdateChannel UpdateChannel { get; private set; } = GlobalConfig.EUpdateChannel.Stable;
internal EUpdateChannel UpdateChannel { get; private set; } = EUpdateChannel.Stable;
[JsonProperty(Required = Required.DisallowNull)]
internal byte HttpTimeout { get; private set; } = 30;
internal ProtocolType SteamProtocol { get; private set; } = ProtocolType.Tcp;
[JsonProperty(Required = Required.DisallowNull)]
internal ulong SteamOwnerID { get; private set; } = 0;
[JsonProperty(Required = Required.DisallowNull)]
internal byte MaxFarmingTime { get; private set; } = 10;
[JsonProperty(Required = Required.DisallowNull)]
internal byte IdleFarmingPeriod { get; private set; } = 3;
[JsonProperty(Required = Required.DisallowNull)]
internal byte FarmingDelay { get; private set; } = 5;
[JsonProperty(Required = Required.DisallowNull)]
internal byte AccountPlayingDelay { get; private set; } = 5;
[JsonProperty(Required = Required.DisallowNull)]
internal byte RequestLimiterDelay { get; private set; } = 7;
internal byte LoginLimiterDelay { get; private set; } = 7;
[JsonProperty(Required = Required.DisallowNull)]
internal byte InventoryLimiterDelay { get; private set; } = 3;
[JsonProperty(Required = Required.DisallowNull)]
internal bool ForceHttp { get; private set; } = false;
[JsonProperty(Required = Required.DisallowNull)]
internal byte HttpTimeout { get; private set; } = 60;
[JsonProperty(Required = Required.DisallowNull)]
internal string WCFHostname { get; private set; } = "localhost";
@@ -62,6 +84,16 @@ namespace ArchiSteamFarm {
[JsonProperty(Required = Required.DisallowNull)]
internal ushort WCFPort { get; private set; } = 1242;
[JsonProperty(Required = Required.DisallowNull)]
internal bool LogToFile { get; private set; } = true;
[JsonProperty(Required = Required.DisallowNull)]
internal bool Statistics { get; private set; } = true;
// TODO: Please remove me immediately after https://github.com/SteamRE/SteamKit/issues/254 gets fixed
[JsonProperty(Required = Required.DisallowNull)]
internal bool HackIgnoreMachineID { get; private set; } = false;
[JsonProperty(Required = Required.DisallowNull)]
internal HashSet<uint> Blacklist { get; private set; } = new HashSet<uint>(GlobalBlacklist);
@@ -79,6 +111,18 @@ namespace ArchiSteamFarm {
return null;
}
// SK2 supports only TCP and UDP steam protocols
// Make sure that user can't screw this up
switch (globalConfig.SteamProtocol) {
case ProtocolType.Tcp:
case ProtocolType.Udp:
break;
default:
Logging.LogGenericWarning("Configured SteamProtocol is invalid: " + globalConfig.SteamProtocol + ", default TCP protocol will be used instead");
globalConfig.SteamProtocol = ProtocolType.Tcp;
break;
}
return globalConfig;
}

View File

@@ -23,7 +23,6 @@
*/
using Newtonsoft.Json;
using SteamAuth;
using System;
using System.IO;

View File

@@ -0,0 +1,122 @@
/*
_ _ _ ____ _ _____
/ \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
/ _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
/ ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
/_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
Copyright 2015-2016 Łukasz "JustArchi" Domeradzki
Contact: JustArchi@JustArchi.net
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
using Newtonsoft.Json;
using SteamKit2;
using System.Collections.Generic;
namespace ArchiSteamFarm {
internal static class Steam {
internal sealed class Item {
// REF: https://developer.valvesoftware.com/wiki/Steam_Web_API/IEconService#CEcon_Asset
[JsonProperty(Required = Required.DisallowNull)]
internal string appid { get; set; }
[JsonProperty(Required = Required.DisallowNull)]
internal string contextid { get; set; }
[JsonProperty(Required = Required.DisallowNull)]
internal string assetid { get; set; }
[JsonProperty(Required = Required.DisallowNull)]
internal string id {
get { return assetid; }
set { assetid = value; }
}
[JsonProperty(Required = Required.AllowNull)]
internal string classid { get; set; }
[JsonProperty(Required = Required.AllowNull)]
internal string instanceid { get; set; }
[JsonProperty(Required = Required.Always)]
internal string amount { get; set; }
}
internal sealed class ItemList {
[JsonProperty(Required = Required.Always)]
internal List<Steam.Item> assets { get; } = new List<Steam.Item>();
}
internal sealed class TradeOffer {
// REF: https://developer.valvesoftware.com/wiki/Steam_Web_API/IEconService#CEcon_TradeOffer
internal enum ETradeOfferState : byte {
Unknown,
Invalid,
Active,
Accepted,
Countered,
Expired,
Canceled,
Declined,
InvalidItems,
EmailPending,
EmailCanceled,
OnHold
}
[JsonProperty(Required = Required.Always)]
internal string tradeofferid { get; set; }
[JsonProperty(Required = Required.Always)]
internal uint accountid_other { get; set; }
[JsonProperty(Required = Required.Always)]
internal ETradeOfferState trade_offer_state { get; set; }
[JsonProperty(Required = Required.Always)]
internal List<Steam.Item> items_to_give { get; } = new List<Steam.Item>();
[JsonProperty(Required = Required.Always)]
internal List<Steam.Item> items_to_receive { get; } = new List<Steam.Item>();
// Extra
private ulong _OtherSteamID64 = 0;
internal ulong OtherSteamID64 {
get {
if (_OtherSteamID64 == 0 && accountid_other != 0) {
_OtherSteamID64 = new SteamID(accountid_other, EUniverse.Public, EAccountType.Individual).ConvertToUInt64();
}
return _OtherSteamID64;
}
}
}
internal sealed class TradeOfferRequest {
[JsonProperty(Required = Required.Always)]
internal bool newversion { get; } = true;
[JsonProperty(Required = Required.Always)]
internal int version { get; } = 2;
[JsonProperty(Required = Required.Always)]
internal Steam.ItemList me { get; } = new Steam.ItemList();
[JsonProperty(Required = Required.Always)]
internal Steam.ItemList them { get; } = new Steam.ItemList();
}
}
}

View File

@@ -31,18 +31,18 @@ namespace ArchiSteamFarm {
internal static class Logging {
private static readonly object FileLock = new object();
internal static bool? LogToFile { get; set; } = null;
private static bool LogToFile = false;
internal static void Init() {
if (!LogToFile.HasValue) {
LogToFile = true;
}
LogToFile = Program.GlobalConfig.LogToFile;
lock (FileLock) {
try {
File.Delete(Program.LogFile);
} catch (Exception e) {
LogGenericException(e);
if (LogToFile) {
lock (FileLock) {
try {
File.Delete(Program.LogFile);
} catch (Exception e) {
LogGenericException(e);
}
}
}
}
@@ -69,11 +69,10 @@ namespace ArchiSteamFarm {
}
Log("[!] EXCEPTION: " + previousMethodName + "() <" + botName + "> " + exception.Message);
Log("[!] StackTrace: " + exception.StackTrace);
Log("[!] StackTrace:" + Environment.NewLine + exception.StackTrace);
Exception innerException = exception.InnerException;
if (innerException != null) {
LogGenericException(innerException, botName, previousMethodName);
if (exception.InnerException != null) {
LogGenericException(exception.InnerException, botName, previousMethodName);
}
}
@@ -119,17 +118,18 @@ namespace ArchiSteamFarm {
// Write on console only when not awaiting response from user
if (!Program.ConsoleIsBusy) {
Console.Write(loggedMessage);
try {
Console.Write(loggedMessage);
} catch { }
}
if (LogToFile.GetValueOrDefault()) {
if (LogToFile) {
lock (FileLock) {
try {
File.AppendAllText(Program.LogFile, loggedMessage);
} catch (Exception e) {
LogToFile = false;
LogGenericException(e);
LogToFile = true;
}
}
}

View File

@@ -27,6 +27,7 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
@@ -34,6 +35,8 @@ using System.Threading.Tasks;
namespace ArchiSteamFarm {
internal static class Program {
internal enum EUserInputType : byte {
Unknown,
DeviceID,
Login,
Password,
PhoneNumber,
@@ -45,13 +48,12 @@ namespace ArchiSteamFarm {
}
internal enum EMode : byte {
Unknown,
Normal, // Standard most common usage
Client, // WCF client only
Server // Normal + WCF server
}
private const string GithubReleaseURL = "https://api.github.com/repos/JustArchi/ArchiSteamFarm/releases";
internal const string ASF = "ASF";
internal const string ConfigDirectory = "config";
internal const string DebugDirectory = "debug";
@@ -59,17 +61,19 @@ namespace ArchiSteamFarm {
internal const string GlobalConfigFile = ASF + ".json";
internal const string GlobalDatabaseFile = ASF + ".db";
private const string GithubReleaseURL = "https://api.github.com/repos/JustArchi/ArchiSteamFarm/releases"; // GitHub API is HTTPS only
private static readonly Assembly Assembly = Assembly.GetExecutingAssembly();
internal static readonly Version Version = Assembly.GetName().Version;
private static readonly object ConsoleLock = new object();
private static readonly SemaphoreSlim SteamSemaphore = new SemaphoreSlim(1);
private static readonly ManualResetEvent ShutdownResetEvent = new ManualResetEvent(false);
private static readonly Assembly Assembly = Assembly.GetExecutingAssembly();
private static readonly string ExecutableFile = Assembly.Location;
private static readonly string ExecutableName = Path.GetFileName(ExecutableFile);
private static readonly string ExecutableDirectory = Path.GetDirectoryName(ExecutableFile);
private static readonly WCF WCF = new WCF();
internal static readonly string Version = Assembly.GetName().Version.ToString();
internal static GlobalConfig GlobalConfig { get; private set; }
internal static GlobalDatabase GlobalDatabase { get; private set; }
internal static bool ConsoleIsBusy { get; private set; } = false;
@@ -77,7 +81,7 @@ namespace ArchiSteamFarm {
private static Timer AutoUpdatesTimer;
private static EMode Mode = EMode.Normal;
private static async Task CheckForUpdate() {
internal static async Task CheckForUpdate() {
string oldExeFile = ExecutableFile + ".old";
// We booted successfully so we can now remove old exe file
@@ -110,7 +114,7 @@ namespace ArchiSteamFarm {
return;
}
GitHub.ReleaseResponse releaseResponse = null;
GitHub.ReleaseResponse releaseResponse;
if (GlobalConfig.UpdateChannel == GlobalConfig.EUpdateChannel.Stable) {
try {
releaseResponse = JsonConvert.DeserializeObject<GitHub.ReleaseResponse>(response);
@@ -140,10 +144,11 @@ namespace ArchiSteamFarm {
return;
}
Logging.LogGenericInfo("Local version: " + Version + " | Remote version: " + releaseResponse.Tag);
Version newVersion = new Version(releaseResponse.Tag);
if (Version.CompareTo(releaseResponse.Tag) >= 0) { // If local version is the same or newer than remote version
// Set up a timer that will automatically update ASF on as-needed basis
Logging.LogGenericInfo("Local version: " + Version + " | Remote version: " + newVersion);
if (Version.CompareTo(newVersion) >= 0) { // If local version is the same or newer than remote version
if (GlobalConfig.AutoUpdates && AutoUpdatesTimer == null) {
Logging.LogGenericInfo("ASF will automatically check for new versions every 24 hours");
AutoUpdatesTimer = new Timer(
@@ -256,8 +261,7 @@ namespace ArchiSteamFarm {
internal static bool Restart() {
try {
// TODO: This probably won't work on Mono, I wonder if I can make it work at some point
if (Process.Start(ExecutableFile, string.Join(" ", Environment.GetCommandLineArgs())) != null) {
if (Process.Start(ExecutableFile, string.Join(" ", Environment.GetCommandLineArgs().Skip(1))) != null) {
Exit();
return true;
} else {
@@ -272,16 +276,23 @@ namespace ArchiSteamFarm {
internal static async Task LimitSteamRequestsAsync() {
await SteamSemaphore.WaitAsync().ConfigureAwait(false);
Task.Run(async () => {
await Utilities.SleepAsync(GlobalConfig.RequestLimiterDelay * 1000).ConfigureAwait(false);
await Utilities.SleepAsync(GlobalConfig.LoginLimiterDelay * 1000).ConfigureAwait(false);
SteamSemaphore.Release();
}).Forget();
}
internal static string GetUserInput(string botLogin, EUserInputType userInputType, string extraInformation = null) {
if (userInputType == EUserInputType.Unknown) {
return null;
}
string result;
lock (ConsoleLock) {
ConsoleIsBusy = true;
switch (userInputType) {
case EUserInputType.DeviceID:
Console.Write("<" + botLogin + "> Please enter your Device ID (including \"android:\"): ");
break;
case EUserInputType.Login:
Console.Write("<" + botLogin + "> Please enter your login: ");
break;
@@ -308,13 +319,16 @@ namespace ArchiSteamFarm {
case EUserInputType.TwoFactorAuthentication:
Console.Write("<" + botLogin + "> Please enter your 2 factor auth code from your authenticator app: ");
break;
default:
Console.Write("<" + botLogin + "> Please enter not documented yet value of \"" + userInputType + "\": ");
break;
}
result = Console.ReadLine();
Console.Clear(); // For security purposes
ConsoleIsBusy = false;
}
return result.Trim(); // Get rid of all whitespace characters
return string.IsNullOrEmpty(result) ? null : result.Trim();
}
internal static void OnBotShutdown() {
@@ -329,13 +343,14 @@ namespace ArchiSteamFarm {
}
Logging.LogGenericInfo("No bots are running, exiting");
Thread.Sleep(5000);
ShutdownResetEvent.Set();
}
private static void InitServices() {
GlobalConfig = GlobalConfig.Load();
if (GlobalConfig == null) {
Logging.LogGenericError("Global config could not be loaded, please make sure that ASF.db exists and is valid!");
Logging.LogGenericError("Global config could not be loaded, please make sure that ASF.json exists and is valid!");
Thread.Sleep(5000);
Exit(1);
}
@@ -357,13 +372,6 @@ namespace ArchiSteamFarm {
switch (arg) {
case "--client":
Mode = EMode.Client;
Logging.LogToFile = false;
break;
case "--log":
Logging.LogToFile = true;
break;
case "--no-log":
Logging.LogToFile = false;
break;
case "--server":
Mode = EMode.Server;
@@ -380,10 +388,10 @@ namespace ArchiSteamFarm {
continue;
}
Logging.LogGenericInfo("Command sent: \"" + arg + "\"");
Logging.LogGenericInfo("Command sent: " + arg);
// We intentionally execute this async block synchronously
Logging.LogGenericInfo("Response received: \"" + WCF.SendCommand(arg) + "\"");
Logging.LogGenericInfo("Response received: " + WCF.SendCommand(arg));
/*
Task.Run(async () => {
Logging.LogGenericNotice("WCF", "Response received: " + await WCF.SendCommand(arg).ConfigureAwait(false));
@@ -402,8 +410,17 @@ namespace ArchiSteamFarm {
Logging.LogGenericException((Exception) args.ExceptionObject);
}
private static void Main(string[] args) {
private static void UnobservedTaskExceptionHandler(object sender, UnobservedTaskExceptionEventArgs args) {
if (sender == null || args == null) {
return;
}
Logging.LogGenericException(args.Exception);
}
private static void Init(string[] args) {
AppDomain.CurrentDomain.UnhandledException += UnhandledExceptionHandler;
TaskScheduler.UnobservedTaskException += UnobservedTaskExceptionHandler;
Logging.LogGenericInfo("Archi's Steam Farm, version " + Version);
Directory.SetCurrentDirectory(ExecutableDirectory);
@@ -426,6 +443,18 @@ namespace ArchiSteamFarm {
}
}
// If debugging is on, we prepare debug directory prior to running
if (GlobalConfig.Debug) {
if (Directory.Exists(DebugDirectory)) {
Directory.Delete(DebugDirectory, true);
Thread.Sleep(1000); // Dirty workaround giving Windows some time to sync
}
Directory.CreateDirectory(DebugDirectory);
SteamKit2.DebugLog.AddListener(new Debugging.DebugListener(Path.Combine(Program.DebugDirectory, "debug.txt")));
SteamKit2.DebugLog.Enabled = true;
}
// Parse args
ParseArgs(args);
@@ -448,6 +477,8 @@ namespace ArchiSteamFarm {
// Before attempting to connect, initialize our list of CMs
Bot.RefreshCMs(GlobalDatabase.CellID).Wait();
bool isRunning = false;
foreach (var configFile in Directory.EnumerateFiles(ConfigDirectory, "*.json")) {
string botName = Path.GetFileNameWithoutExtension(configFile);
if (botName.Equals(ASF)) {
@@ -455,7 +486,9 @@ namespace ArchiSteamFarm {
}
Bot bot = new Bot(botName);
if (!bot.BotConfig.Enabled) {
if (bot.BotConfig != null && bot.BotConfig.Enabled) {
isRunning = true;
} else {
Logging.LogGenericInfo("Not starting this instance because it's disabled in config file", botName);
}
}
@@ -465,23 +498,28 @@ namespace ArchiSteamFarm {
string botName = Path.GetFileNameWithoutExtension(configFile);
Logging.LogGenericWarning("Found legacy " + botName + ".xml config file, it will now be converted to new ASF V2.0 format!");
Bot bot = new Bot(botName);
if (!bot.BotConfig.Enabled) {
if (bot.BotConfig != null && bot.BotConfig.Enabled) {
isRunning = true;
} else {
Logging.LogGenericInfo("Not starting this instance because it's disabled in config file", botName);
}
}
// CONVERSION END
// Check if we got any bots running
OnBotShutdown();
if (!isRunning) {
OnBotShutdown();
}
}
private static void Main(string[] args) {
Init(args);
// Wait for signal to shutdown
ShutdownResetEvent.WaitOne();
// We got a signal to shutdown, consider giving user some time to read the message
Thread.Sleep(5000);
// This is over, cleanup only now
WCF.StopServer();
// We got a signal to shutdown
Environment.Exit(0);
}
}
}

View File

@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("2.0.0.2")]
[assembly: AssemblyFileVersion("2.0.0.2")]
[assembly: AssemblyVersion("2.0.1.4")]
[assembly: AssemblyFileVersion("2.0.1.4")]

View File

@@ -1,55 +0,0 @@
/*
_ _ _ ____ _ _____
/ \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
/ _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
/ ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
/_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
Copyright 2015-2016 Łukasz "JustArchi" Domeradzki
Contact: JustArchi@JustArchi.net
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
using Newtonsoft.Json;
namespace ArchiSteamFarm {
internal sealed class SteamItem {
// REF: https://developer.valvesoftware.com/wiki/Steam_Web_API/IEconService#CEcon_Asset
[JsonProperty(Required = Required.DisallowNull)]
internal string appid { get; set; }
[JsonProperty(Required = Required.DisallowNull)]
internal string contextid { get; set; }
[JsonProperty(Required = Required.DisallowNull)]
internal string assetid { get; set; }
[JsonProperty(Required = Required.DisallowNull)]
internal string id {
get { return assetid; }
set { assetid = value; }
}
[JsonProperty(Required = Required.AllowNull)]
internal string classid { get; set; }
[JsonProperty(Required = Required.AllowNull)]
internal string instanceid { get; set; }
[JsonProperty(Required = Required.Always)]
internal string amount { get; set; }
}
}

View File

@@ -1,33 +0,0 @@
/*
_ _ _ ____ _ _____
/ \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
/ _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
/ ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
/_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
Copyright 2015-2016 Łukasz "JustArchi" Domeradzki
Contact: JustArchi@JustArchi.net
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
using Newtonsoft.Json;
using System.Collections.Generic;
namespace ArchiSteamFarm {
internal sealed class SteamItemList {
[JsonProperty(Required = Required.Always)]
internal List<SteamItem> assets { get; } = new List<SteamItem>();
}
}

View File

@@ -1,74 +0,0 @@
/*
_ _ _ ____ _ _____
/ \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
/ _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
/ ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
/_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
Copyright 2015-2016 Łukasz "JustArchi" Domeradzki
Contact: JustArchi@JustArchi.net
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
using Newtonsoft.Json;
using SteamKit2;
using System.Collections.Generic;
namespace ArchiSteamFarm {
internal sealed class SteamTradeOffer {
// REF: https://developer.valvesoftware.com/wiki/Steam_Web_API/IEconService#CEcon_TradeOffer
internal enum ETradeOfferState : byte {
Unknown,
Invalid,
Active,
Accepted,
Countered,
Expired,
Canceled,
Declined,
InvalidItems,
EmailPending,
EmailCanceled,
OnHold
}
[JsonProperty(Required = Required.Always)]
internal string tradeofferid { get; set; }
[JsonProperty(Required = Required.Always)]
internal int accountid_other { get; set; }
[JsonProperty(Required = Required.Always)]
internal ETradeOfferState trade_offer_state { get; set; }
[JsonProperty(Required = Required.Always)]
internal List<SteamItem> items_to_give { get; } = new List<SteamItem>();
[JsonProperty(Required = Required.Always)]
internal List<SteamItem> items_to_receive { get; } = new List<SteamItem>();
// Extra
private ulong _OtherSteamID64 = 0;
internal ulong OtherSteamID64 {
get {
if (_OtherSteamID64 == 0 && accountid_other != 0) {
_OtherSteamID64 = new SteamID((uint) accountid_other, EUniverse.Public, EAccountType.Individual).ConvertToUInt64();
}
return _OtherSteamID64;
}
}
}
}

View File

@@ -1,41 +0,0 @@
/*
_ _ _ ____ _ _____
/ \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
/ _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
/ ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
/_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
Copyright 2015-2016 Łukasz "JustArchi" Domeradzki
Contact: JustArchi@JustArchi.net
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
using Newtonsoft.Json;
namespace ArchiSteamFarm {
internal sealed class SteamTradeOfferRequest {
[JsonProperty(Required = Required.Always)]
internal bool newversion { get; } = true;
[JsonProperty(Required = Required.Always)]
internal int version { get; } = 2;
[JsonProperty(Required = Required.Always)]
internal SteamItemList me { get; } = new SteamItemList();
[JsonProperty(Required = Required.Always)]
internal SteamItemList them { get; } = new SteamItemList();
}
}

View File

@@ -22,6 +22,7 @@
*/
using SteamAuth;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
@@ -35,50 +36,57 @@ namespace ArchiSteamFarm {
private readonly Bot Bot;
private readonly SemaphoreSlim Semaphore = new SemaphoreSlim(1);
private volatile byte ParsingTasks = 0;
internal static async Task LimitInventoryRequestsAsync() {
await InventorySemaphore.WaitAsync().ConfigureAwait(false);
Task.Run(async () => {
await Utilities.SleepAsync(Program.GlobalConfig.RequestLimiterDelay * 1000).ConfigureAwait(false);
await Utilities.SleepAsync(Program.GlobalConfig.InventoryLimiterDelay * 1000).ConfigureAwait(false);
InventorySemaphore.Release();
}).Forget();
}
internal Trading(Bot bot) {
if (bot == null) {
return;
}
Bot = bot;
}
internal async void CheckTrades() {
if (ParsingTasks < 2) {
ParsingTasks++;
await Semaphore.WaitAsync().ConfigureAwait(false);
await ParseActiveTrades().ConfigureAwait(false);
Semaphore.Release();
ParsingTasks--;
if (ParsingTasks >= 2) {
return;
}
ParsingTasks++;
await Semaphore.WaitAsync().ConfigureAwait(false);
await ParseActiveTrades().ConfigureAwait(false);
Semaphore.Release();
ParsingTasks--;
}
private async Task ParseActiveTrades() {
List<SteamTradeOffer> tradeOffers = Bot.ArchiWebHandler.GetTradeOffers();
List<Steam.TradeOffer> tradeOffers = Bot.ArchiWebHandler.GetTradeOffers();
if (tradeOffers == null) {
return;
}
List<Task> tasks = new List<Task>();
foreach (SteamTradeOffer tradeOffer in tradeOffers) {
if (tradeOffer.trade_offer_state == SteamTradeOffer.ETradeOfferState.Active) {
foreach (Steam.TradeOffer tradeOffer in tradeOffers) {
if (tradeOffer.trade_offer_state == Steam.TradeOffer.ETradeOfferState.Active) {
tasks.Add(Task.Run(async () => await ParseTrade(tradeOffer).ConfigureAwait(false)));
}
}
await Task.WhenAll(tasks).ConfigureAwait(false);
await Bot.AcceptAllConfirmations().ConfigureAwait(false);
await Bot.AcceptConfirmations(Confirmation.ConfirmationType.Trade).ConfigureAwait(false);
}
private async Task ParseTrade(SteamTradeOffer tradeOffer) {
private async Task ParseTrade(Steam.TradeOffer tradeOffer) {
if (tradeOffer == null) {
return;
}

View File

@@ -23,6 +23,7 @@
*/
using System;
using System.Linq;
using System.ServiceModel;
using System.ServiceModel.Channels;
@@ -100,7 +101,7 @@ namespace ArchiSteamFarm {
if (args.Length > 1) { // If we have args[1] provided, use given botName
botName = args[1];
} else { // If not, just pick first one
botName = Bot.GetAnyBotName();
botName = Bot.Bots.Keys.FirstOrDefault();
}
if (string.IsNullOrEmpty(botName)) {
@@ -112,12 +113,12 @@ namespace ArchiSteamFarm {
return "ERROR: Couldn't find any bot named: " + botName;
}
Logging.LogGenericInfo("Received command: \"" + input + "\"");
Logging.LogGenericInfo("Received command: " + input);
string command = '!' + input;
string output = bot.HandleMessage(command).Result; // TODO: This should be asynchronous
string output = bot.Response(Program.GlobalConfig.SteamOwnerID, command).Result; // TODO: This should be asynchronous
Logging.LogGenericInfo("Answered to command: \"" + input + "\" with: \"" + output + "\"");
Logging.LogGenericInfo("Answered to command: " + input + " with: " + output);
return output;
}
}

View File

@@ -31,18 +31,20 @@ using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
namespace ArchiSteamFarm {
internal static class WebBrowser {
internal const byte MaxConnections = 10; // Defines maximum number of connections per ServicePoint. Be careful, as it also defines maximum number of sockets in CLOSE_WAIT state
internal const byte MaxIdleTime = 15; // In seconds, how long socket is allowed to stay in CLOSE_WAIT state after there are no connections to it
internal const byte MaxRetries = 5; // Defines maximum number of retries, UrlRequest() does not handle retry by itself (it's app responsibility)
private const byte MaxConnections = 10; // Defines maximum number of connections per ServicePoint. Be careful, as it also defines maximum number of sockets in CLOSE_WAIT state
private const byte MaxIdleTime = 15; // In seconds, how long socket is allowed to stay in CLOSE_WAIT state after there are no connections to it
private static readonly string DefaultUserAgent = "ArchiSteamFarm/" + Program.Version;
private static readonly HttpClient HttpClient = new HttpClient(new HttpClientHandler {
UseCookies = false
}) {
Timeout = TimeSpan.FromSeconds(30)
Timeout = TimeSpan.FromSeconds(60)
};
internal static void Init() {
@@ -155,6 +157,28 @@ namespace ArchiSteamFarm {
return jObject;
}
internal static async Task<XmlDocument> UrlGetToXML(string request, Dictionary<string, string> cookies = null, string referer = null) {
if (string.IsNullOrEmpty(request)) {
return null;
}
string content = await UrlGetToContent(request, cookies, referer).ConfigureAwait(false);
if (string.IsNullOrEmpty(content)) {
return null;
}
XmlDocument xmlDocument = new XmlDocument();
try {
xmlDocument.LoadXml(content);
} catch (XmlException e) {
Logging.LogGenericException(e);
return null;
}
return xmlDocument;
}
private static async Task<HttpResponseMessage> UrlRequest(string request, HttpMethod httpMethod, Dictionary<string, string> data = null, Dictionary<string, string> cookies = null, string referer = null) {
if (string.IsNullOrEmpty(request) || httpMethod == null) {
return null;

View File

@@ -2,11 +2,21 @@
"Debug": false,
"AutoUpdates": true,
"UpdateChannel": 1,
"HttpTimeout": 30,
"SteamProtocol": 6,
"SteamOwnerID": 0,
"MaxFarmingTime": 10,
"IdleFarmingPeriod": 3,
"FarmingDelay": 5,
"AccountPlayingDelay": 5,
"RequestLimiterDelay": 7,
"LoginLimiterDelay": 7,
"InventoryLimiterDelay": 3,
"ForceHttp": false,
"HttpTimeout": 60,
"WCFHostname": "localhost",
"WCFPort": 1242,
"LogToFile": true,
"Statistics": true,
"HackIgnoreMachineID": false,
"Blacklist": [
267420,
303700,

View File

@@ -18,9 +18,9 @@
"SendOnFarmingFinished": false,
"SteamTradeToken": null,
"SendTradePeriod": 0,
"AcceptConfirmationsPeriod": 0,
"CustomGamePlayedWhileIdle": null,
"GamesPlayedWhileIdle": [
0
],
"Statistics": true
]
}

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="HtmlAgilityPack" version="1.4.9" targetFramework="net45" />
<package id="Newtonsoft.Json" version="8.0.2" targetFramework="net452" />
<package id="Newtonsoft.Json" version="8.0.3" targetFramework="net451" />
<package id="protobuf-net" version="2.0.0.668" targetFramework="net45" />
<package id="SteamKit2" version="1.7.0" targetFramework="net452" />
</packages>

View File

@@ -8,8 +8,29 @@ namespace SteamAuth
{
public class Confirmation
{
public string ConfirmationID;
public string ConfirmationKey;
public string ConfirmationDescription;
public string ID;
public string Key;
public string Description;
public ConfirmationType ConfType
{
get
{
if (String.IsNullOrEmpty(Description)) return ConfirmationType.Unknown;
if (Description.StartsWith("Confirm ")) return ConfirmationType.GenericConfirmation;
if (Description.StartsWith("Trade with ")) return ConfirmationType.Trade;
if (Description.StartsWith("Sell -")) return ConfirmationType.MarketSellTransaction;
return ConfirmationType.Unknown;
}
}
public enum ConfirmationType
{
GenericConfirmation,
Trade,
MarketSellTransaction,
Unknown
}
}
}

View File

@@ -33,7 +33,7 @@
</PropertyGroup>
<ItemGroup>
<Reference Include="Newtonsoft.Json, Version=8.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.8.0.2\lib\net45\Newtonsoft.Json.dll</HintPath>
<HintPath>..\packages\Newtonsoft.Json.8.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System" />

View File

@@ -71,7 +71,7 @@ namespace SteamAuth
if (removeResponse == null || removeResponse.Response == null || !removeResponse.Response.Success) return false;
return true;
}
catch (Exception e)
catch (Exception)
{
return false;
}
@@ -115,7 +115,7 @@ namespace SteamAuth
codePoint /= steamGuardCodeTranslations.Length;
}
}
catch (Exception e)
catch (Exception)
{
return null; //Change later, catch-alls are bad!
}
@@ -162,9 +162,9 @@ namespace SteamAuth
string confDesc = confDescs[i].Groups[1].Value;
Confirmation conf = new Confirmation()
{
ConfirmationDescription = confDesc,
ConfirmationID = confID,
ConfirmationKey = confKey
Description = confDesc,
ID = confID,
Key = confKey
};
ret.Add(conf);
}
@@ -212,9 +212,9 @@ namespace SteamAuth
string confDesc = confDescs[i].Groups[1].Value;
Confirmation conf = new Confirmation()
{
ConfirmationDescription = confDesc,
ConfirmationID = confID,
ConfirmationKey = confKey
Description = confDesc,
ID = confID,
Key = confKey
};
ret.Add(conf);
}
@@ -268,7 +268,7 @@ namespace SteamAuth
this.Session.SteamLoginSecure = tokenSecure;
return true;
}
catch (Exception e)
catch (Exception)
{
return false;
}
@@ -300,7 +300,7 @@ namespace SteamAuth
this.Session.SteamLoginSecure = tokenSecure;
return true;
}
catch (Exception e)
catch (Exception)
{
return false;
}
@@ -308,7 +308,7 @@ namespace SteamAuth
private ConfirmationDetailsResponse _getConfirmationDetails(Confirmation conf)
{
string url = APIEndpoints.COMMUNITY_BASE + "/mobileconf/details/" + conf.ConfirmationID + "?";
string url = APIEndpoints.COMMUNITY_BASE + "/mobileconf/details/" + conf.ID + "?";
string queryString = GenerateConfirmationQueryParams("details");
url += queryString;
@@ -329,7 +329,7 @@ namespace SteamAuth
string url = APIEndpoints.COMMUNITY_BASE + "/mobileconf/ajaxop";
string queryString = "?op=" + op + "&";
queryString += GenerateConfirmationQueryParams(op);
queryString += "&cid=" + conf.ConfirmationID + "&ck=" + conf.ConfirmationKey;
queryString += "&cid=" + conf.ID + "&ck=" + conf.Key;
url += queryString;
CookieContainer cookies = new CookieContainer();
@@ -401,7 +401,7 @@ namespace SteamAuth
string hash = WebUtility.UrlEncode(encodedData);
return hash;
}
catch (Exception e)
catch (Exception)
{
return null; //Fix soon: catch-all is BAD!
}

View File

@@ -161,8 +161,6 @@ namespace SteamAuth
this.LoggedIn = true;
return LoginResult.LoginOkay;
}
return LoginResult.GeneralFailure;
}
private class LoginResponse

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Newtonsoft.Json" version="8.0.2" targetFramework="net452" />
<package id="Newtonsoft.Json" version="8.0.3" targetFramework="net451" />
</packages>

Binary file not shown.

Binary file not shown.

View File

@@ -604,6 +604,12 @@
Initializes a new instance of the <see cref="T:Newtonsoft.Json.Converters.StringEnumConverter"/> class.
</summary>
</member>
<member name="M:Newtonsoft.Json.Converters.StringEnumConverter.#ctor(System.Boolean)">
<summary>
Initializes a new instance of the <see cref="T:Newtonsoft.Json.Converters.StringEnumConverter"/> class.
</summary>
<param name="camelCaseText"><c>true</c> if the written enum text will be camel case; otherwise, <c>false</c>.</param>
</member>
<member name="M:Newtonsoft.Json.Converters.StringEnumConverter.WriteJson(Newtonsoft.Json.JsonWriter,System.Object,Newtonsoft.Json.JsonSerializer)">
<summary>
Writes the JSON representation of the object.
@@ -1058,6 +1064,12 @@
</summary>
<value>The method used when merging JSON arrays.</value>
</member>
<member name="P:Newtonsoft.Json.Linq.JsonMergeSettings.MergeNullValueHandling">
<summary>
Gets or sets how how null value properties are merged.
</summary>
<value>How null value properties are merged.</value>
</member>
<member name="T:Newtonsoft.Json.Linq.MergeArrayHandling">
<summary>
Specifies how JSON arrays are merged together.
@@ -1075,6 +1087,21 @@
<member name="F:Newtonsoft.Json.Linq.MergeArrayHandling.Merge">
<summary>Merge array items together, matched by index.</summary>
</member>
<member name="T:Newtonsoft.Json.Linq.MergeNullValueHandling">
<summary>
Specifies how null value properties are merged.
</summary>
</member>
<member name="F:Newtonsoft.Json.Linq.MergeNullValueHandling.Ignore">
<summary>
The content's null value properties will be ignored during merging.
</summary>
</member>
<member name="F:Newtonsoft.Json.Linq.MergeNullValueHandling.Merge">
<summary>
The content's null value properties will be merged.
</summary>
</member>
<member name="T:Newtonsoft.Json.Linq.JPropertyDescriptor">
<summary>
Represents a view of a <see cref="T:Newtonsoft.Json.Linq.JProperty"/>.
@@ -3511,9 +3538,9 @@
</member>
<member name="M:Newtonsoft.Json.Linq.JValue.CreateUndefined">
<summary>
Creates a <see cref="T:Newtonsoft.Json.Linq.JValue"/> null value.
Creates a <see cref="T:Newtonsoft.Json.Linq.JValue"/> undefined value.
</summary>
<returns>A <see cref="T:Newtonsoft.Json.Linq.JValue"/> null value.</returns>
<returns>A <see cref="T:Newtonsoft.Json.Linq.JValue"/> undefined value.</returns>
</member>
<member name="P:Newtonsoft.Json.Linq.JValue.Type">
<summary>
@@ -6646,7 +6673,7 @@
</member>
<member name="F:Newtonsoft.Json.MemberSerialization.OptIn">
<summary>
Only members must be marked with <see cref="T:Newtonsoft.Json.JsonPropertyAttribute"/> or <see cref="!:DataMemberAttribute"/> are serialized.
Only members marked with <see cref="T:Newtonsoft.Json.JsonPropertyAttribute"/> or <see cref="!:DataMemberAttribute"/> are serialized.
This member serialization mode can also be set by marking the class with <see cref="!:DataContractAttribute"/>.
</summary>
</member>

Binary file not shown.

View File

@@ -627,6 +627,12 @@
Initializes a new instance of the <see cref="T:Newtonsoft.Json.Converters.StringEnumConverter"/> class.
</summary>
</member>
<member name="M:Newtonsoft.Json.Converters.StringEnumConverter.#ctor(System.Boolean)">
<summary>
Initializes a new instance of the <see cref="T:Newtonsoft.Json.Converters.StringEnumConverter"/> class.
</summary>
<param name="camelCaseText"><c>true</c> if the written enum text will be camel case; otherwise, <c>false</c>.</param>
</member>
<member name="M:Newtonsoft.Json.Converters.StringEnumConverter.WriteJson(Newtonsoft.Json.JsonWriter,System.Object,Newtonsoft.Json.JsonSerializer)">
<summary>
Writes the JSON representation of the object.
@@ -1190,6 +1196,12 @@
</summary>
<value>The method used when merging JSON arrays.</value>
</member>
<member name="P:Newtonsoft.Json.Linq.JsonMergeSettings.MergeNullValueHandling">
<summary>
Gets or sets how how null value properties are merged.
</summary>
<value>How null value properties are merged.</value>
</member>
<member name="T:Newtonsoft.Json.Linq.MergeArrayHandling">
<summary>
Specifies how JSON arrays are merged together.
@@ -1207,6 +1219,21 @@
<member name="F:Newtonsoft.Json.Linq.MergeArrayHandling.Merge">
<summary>Merge array items together, matched by index.</summary>
</member>
<member name="T:Newtonsoft.Json.Linq.MergeNullValueHandling">
<summary>
Specifies how null value properties are merged.
</summary>
</member>
<member name="F:Newtonsoft.Json.Linq.MergeNullValueHandling.Ignore">
<summary>
The content's null value properties will be ignored during merging.
</summary>
</member>
<member name="F:Newtonsoft.Json.Linq.MergeNullValueHandling.Merge">
<summary>
The content's null value properties will be merged.
</summary>
</member>
<member name="T:Newtonsoft.Json.Linq.JRaw">
<summary>
Represents a raw JSON string.
@@ -3605,9 +3632,9 @@
</member>
<member name="M:Newtonsoft.Json.Linq.JValue.CreateUndefined">
<summary>
Creates a <see cref="T:Newtonsoft.Json.Linq.JValue"/> null value.
Creates a <see cref="T:Newtonsoft.Json.Linq.JValue"/> undefined value.
</summary>
<returns>A <see cref="T:Newtonsoft.Json.Linq.JValue"/> null value.</returns>
<returns>A <see cref="T:Newtonsoft.Json.Linq.JValue"/> undefined value.</returns>
</member>
<member name="P:Newtonsoft.Json.Linq.JValue.Type">
<summary>
@@ -5688,7 +5715,7 @@
</member>
<member name="F:Newtonsoft.Json.MemberSerialization.OptIn">
<summary>
Only members must be marked with <see cref="T:Newtonsoft.Json.JsonPropertyAttribute"/> or <see cref="T:System.Runtime.Serialization.DataMemberAttribute"/> are serialized.
Only members marked with <see cref="T:Newtonsoft.Json.JsonPropertyAttribute"/> or <see cref="T:System.Runtime.Serialization.DataMemberAttribute"/> are serialized.
This member serialization mode can also be set by marking the class with <see cref="T:System.Runtime.Serialization.DataContractAttribute"/>.
</summary>
</member>

Binary file not shown.

View File

@@ -699,6 +699,12 @@
Initializes a new instance of the <see cref="T:Newtonsoft.Json.Converters.StringEnumConverter"/> class.
</summary>
</member>
<member name="M:Newtonsoft.Json.Converters.StringEnumConverter.#ctor(System.Boolean)">
<summary>
Initializes a new instance of the <see cref="T:Newtonsoft.Json.Converters.StringEnumConverter"/> class.
</summary>
<param name="camelCaseText"><c>true</c> if the written enum text will be camel case; otherwise, <c>false</c>.</param>
</member>
<member name="M:Newtonsoft.Json.Converters.StringEnumConverter.WriteJson(Newtonsoft.Json.JsonWriter,System.Object,Newtonsoft.Json.JsonSerializer)">
<summary>
Writes the JSON representation of the object.
@@ -1173,6 +1179,12 @@
</summary>
<value>The method used when merging JSON arrays.</value>
</member>
<member name="P:Newtonsoft.Json.Linq.JsonMergeSettings.MergeNullValueHandling">
<summary>
Gets or sets how how null value properties are merged.
</summary>
<value>How null value properties are merged.</value>
</member>
<member name="T:Newtonsoft.Json.Linq.MergeArrayHandling">
<summary>
Specifies how JSON arrays are merged together.
@@ -1190,6 +1202,21 @@
<member name="F:Newtonsoft.Json.Linq.MergeArrayHandling.Merge">
<summary>Merge array items together, matched by index.</summary>
</member>
<member name="T:Newtonsoft.Json.Linq.MergeNullValueHandling">
<summary>
Specifies how null value properties are merged.
</summary>
</member>
<member name="F:Newtonsoft.Json.Linq.MergeNullValueHandling.Ignore">
<summary>
The content's null value properties will be ignored during merging.
</summary>
</member>
<member name="F:Newtonsoft.Json.Linq.MergeNullValueHandling.Merge">
<summary>
The content's null value properties will be merged.
</summary>
</member>
<member name="T:Newtonsoft.Json.Linq.JRaw">
<summary>
Represents a raw JSON string.
@@ -3715,9 +3742,9 @@
</member>
<member name="M:Newtonsoft.Json.Linq.JValue.CreateUndefined">
<summary>
Creates a <see cref="T:Newtonsoft.Json.Linq.JValue"/> null value.
Creates a <see cref="T:Newtonsoft.Json.Linq.JValue"/> undefined value.
</summary>
<returns>A <see cref="T:Newtonsoft.Json.Linq.JValue"/> null value.</returns>
<returns>A <see cref="T:Newtonsoft.Json.Linq.JValue"/> undefined value.</returns>
</member>
<member name="P:Newtonsoft.Json.Linq.JValue.Type">
<summary>
@@ -5896,7 +5923,7 @@
</member>
<member name="F:Newtonsoft.Json.MemberSerialization.OptIn">
<summary>
Only members must be marked with <see cref="T:Newtonsoft.Json.JsonPropertyAttribute"/> or <see cref="T:System.Runtime.Serialization.DataMemberAttribute"/> are serialized.
Only members marked with <see cref="T:Newtonsoft.Json.JsonPropertyAttribute"/> or <see cref="T:System.Runtime.Serialization.DataMemberAttribute"/> are serialized.
This member serialization mode can also be set by marking the class with <see cref="T:System.Runtime.Serialization.DataContractAttribute"/>.
</summary>
</member>

Binary file not shown.

View File

@@ -778,6 +778,12 @@
Initializes a new instance of the <see cref="T:Newtonsoft.Json.Converters.StringEnumConverter"/> class.
</summary>
</member>
<member name="M:Newtonsoft.Json.Converters.StringEnumConverter.#ctor(System.Boolean)">
<summary>
Initializes a new instance of the <see cref="T:Newtonsoft.Json.Converters.StringEnumConverter"/> class.
</summary>
<param name="camelCaseText"><c>true</c> if the written enum text will be camel case; otherwise, <c>false</c>.</param>
</member>
<member name="M:Newtonsoft.Json.Converters.StringEnumConverter.WriteJson(Newtonsoft.Json.JsonWriter,System.Object,Newtonsoft.Json.JsonSerializer)">
<summary>
Writes the JSON representation of the object.
@@ -5094,6 +5100,12 @@
</summary>
<value>The method used when merging JSON arrays.</value>
</member>
<member name="P:Newtonsoft.Json.Linq.JsonMergeSettings.MergeNullValueHandling">
<summary>
Gets or sets how how null value properties are merged.
</summary>
<value>How null value properties are merged.</value>
</member>
<member name="T:Newtonsoft.Json.Linq.JProperty">
<summary>
Represents a JSON property.
@@ -6670,9 +6682,9 @@
</member>
<member name="M:Newtonsoft.Json.Linq.JValue.CreateUndefined">
<summary>
Creates a <see cref="T:Newtonsoft.Json.Linq.JValue"/> null value.
Creates a <see cref="T:Newtonsoft.Json.Linq.JValue"/> undefined value.
</summary>
<returns>A <see cref="T:Newtonsoft.Json.Linq.JValue"/> null value.</returns>
<returns>A <see cref="T:Newtonsoft.Json.Linq.JValue"/> undefined value.</returns>
</member>
<member name="P:Newtonsoft.Json.Linq.JValue.Type">
<summary>
@@ -6821,6 +6833,21 @@
<member name="F:Newtonsoft.Json.Linq.MergeArrayHandling.Merge">
<summary>Merge array items together, matched by index.</summary>
</member>
<member name="T:Newtonsoft.Json.Linq.MergeNullValueHandling">
<summary>
Specifies how null value properties are merged.
</summary>
</member>
<member name="F:Newtonsoft.Json.Linq.MergeNullValueHandling.Ignore">
<summary>
The content's null value properties will be ignored during merging.
</summary>
</member>
<member name="F:Newtonsoft.Json.Linq.MergeNullValueHandling.Merge">
<summary>
The content's null value properties will be merged.
</summary>
</member>
<member name="T:Newtonsoft.Json.MemberSerialization">
<summary>
Specifies the member serialization options for the <see cref="T:Newtonsoft.Json.JsonSerializer"/>.
@@ -6834,7 +6861,7 @@
</member>
<member name="F:Newtonsoft.Json.MemberSerialization.OptIn">
<summary>
Only members must be marked with <see cref="T:Newtonsoft.Json.JsonPropertyAttribute"/> or <see cref="T:System.Runtime.Serialization.DataMemberAttribute"/> are serialized.
Only members marked with <see cref="T:Newtonsoft.Json.JsonPropertyAttribute"/> or <see cref="T:System.Runtime.Serialization.DataMemberAttribute"/> are serialized.
This member serialization mode can also be set by marking the class with <see cref="T:System.Runtime.Serialization.DataContractAttribute"/>.
</summary>
</member>

View File

@@ -610,6 +610,12 @@
Initializes a new instance of the <see cref="T:Newtonsoft.Json.Converters.StringEnumConverter"/> class.
</summary>
</member>
<member name="M:Newtonsoft.Json.Converters.StringEnumConverter.#ctor(System.Boolean)">
<summary>
Initializes a new instance of the <see cref="T:Newtonsoft.Json.Converters.StringEnumConverter"/> class.
</summary>
<param name="camelCaseText"><c>true</c> if the written enum text will be camel case; otherwise, <c>false</c>.</param>
</member>
<member name="M:Newtonsoft.Json.Converters.StringEnumConverter.WriteJson(Newtonsoft.Json.JsonWriter,System.Object,Newtonsoft.Json.JsonSerializer)">
<summary>
Writes the JSON representation of the object.
@@ -4588,6 +4594,12 @@
</summary>
<value>The method used when merging JSON arrays.</value>
</member>
<member name="P:Newtonsoft.Json.Linq.JsonMergeSettings.MergeNullValueHandling">
<summary>
Gets or sets how how null value properties are merged.
</summary>
<value>How null value properties are merged.</value>
</member>
<member name="T:Newtonsoft.Json.Linq.JToken">
<summary>
Represents an abstract JSON token.
@@ -5961,9 +5973,9 @@
</member>
<member name="M:Newtonsoft.Json.Linq.JValue.CreateUndefined">
<summary>
Creates a <see cref="T:Newtonsoft.Json.Linq.JValue"/> null value.
Creates a <see cref="T:Newtonsoft.Json.Linq.JValue"/> undefined value.
</summary>
<returns>A <see cref="T:Newtonsoft.Json.Linq.JValue"/> null value.</returns>
<returns>A <see cref="T:Newtonsoft.Json.Linq.JValue"/> undefined value.</returns>
</member>
<member name="P:Newtonsoft.Json.Linq.JValue.Type">
<summary>
@@ -6086,6 +6098,21 @@
<member name="F:Newtonsoft.Json.Linq.MergeArrayHandling.Merge">
<summary>Merge array items together, matched by index.</summary>
</member>
<member name="T:Newtonsoft.Json.Linq.MergeNullValueHandling">
<summary>
Specifies how null value properties are merged.
</summary>
</member>
<member name="F:Newtonsoft.Json.Linq.MergeNullValueHandling.Ignore">
<summary>
The content's null value properties will be ignored during merging.
</summary>
</member>
<member name="F:Newtonsoft.Json.Linq.MergeNullValueHandling.Merge">
<summary>
The content's null value properties will be merged.
</summary>
</member>
<member name="T:Newtonsoft.Json.MemberSerialization">
<summary>
Specifies the member serialization options for the <see cref="T:Newtonsoft.Json.JsonSerializer"/>.
@@ -6099,7 +6126,7 @@
</member>
<member name="F:Newtonsoft.Json.MemberSerialization.OptIn">
<summary>
Only members must be marked with <see cref="T:Newtonsoft.Json.JsonPropertyAttribute"/> or <see cref="T:System.Runtime.Serialization.DataMemberAttribute"/> are serialized.
Only members marked with <see cref="T:Newtonsoft.Json.JsonPropertyAttribute"/> or <see cref="T:System.Runtime.Serialization.DataMemberAttribute"/> are serialized.
This member serialization mode can also be set by marking the class with <see cref="T:System.Runtime.Serialization.DataContractAttribute"/>.
</summary>
</member>

View File

@@ -650,6 +650,12 @@
Initializes a new instance of the <see cref="T:Newtonsoft.Json.Converters.StringEnumConverter"/> class.
</summary>
</member>
<member name="M:Newtonsoft.Json.Converters.StringEnumConverter.#ctor(System.Boolean)">
<summary>
Initializes a new instance of the <see cref="T:Newtonsoft.Json.Converters.StringEnumConverter"/> class.
</summary>
<param name="camelCaseText"><c>true</c> if the written enum text will be camel case; otherwise, <c>false</c>.</param>
</member>
<member name="M:Newtonsoft.Json.Converters.StringEnumConverter.WriteJson(Newtonsoft.Json.JsonWriter,System.Object,Newtonsoft.Json.JsonSerializer)">
<summary>
Writes the JSON representation of the object.
@@ -4858,6 +4864,12 @@
</summary>
<value>The method used when merging JSON arrays.</value>
</member>
<member name="P:Newtonsoft.Json.Linq.JsonMergeSettings.MergeNullValueHandling">
<summary>
Gets or sets how how null value properties are merged.
</summary>
<value>How null value properties are merged.</value>
</member>
<member name="T:Newtonsoft.Json.Linq.JToken">
<summary>
Represents an abstract JSON token.
@@ -6249,9 +6261,9 @@
</member>
<member name="M:Newtonsoft.Json.Linq.JValue.CreateUndefined">
<summary>
Creates a <see cref="T:Newtonsoft.Json.Linq.JValue"/> null value.
Creates a <see cref="T:Newtonsoft.Json.Linq.JValue"/> undefined value.
</summary>
<returns>A <see cref="T:Newtonsoft.Json.Linq.JValue"/> null value.</returns>
<returns>A <see cref="T:Newtonsoft.Json.Linq.JValue"/> undefined value.</returns>
</member>
<member name="P:Newtonsoft.Json.Linq.JValue.Type">
<summary>
@@ -6383,6 +6395,21 @@
<member name="F:Newtonsoft.Json.Linq.MergeArrayHandling.Merge">
<summary>Merge array items together, matched by index.</summary>
</member>
<member name="T:Newtonsoft.Json.Linq.MergeNullValueHandling">
<summary>
Specifies how null value properties are merged.
</summary>
</member>
<member name="F:Newtonsoft.Json.Linq.MergeNullValueHandling.Ignore">
<summary>
The content's null value properties will be ignored during merging.
</summary>
</member>
<member name="F:Newtonsoft.Json.Linq.MergeNullValueHandling.Merge">
<summary>
The content's null value properties will be merged.
</summary>
</member>
<member name="T:Newtonsoft.Json.MemberSerialization">
<summary>
Specifies the member serialization options for the <see cref="T:Newtonsoft.Json.JsonSerializer"/>.
@@ -6396,7 +6423,7 @@
</member>
<member name="F:Newtonsoft.Json.MemberSerialization.OptIn">
<summary>
Only members must be marked with <see cref="T:Newtonsoft.Json.JsonPropertyAttribute"/> or <see cref="T:System.Runtime.Serialization.DataMemberAttribute"/> are serialized.
Only members marked with <see cref="T:Newtonsoft.Json.JsonPropertyAttribute"/> or <see cref="T:System.Runtime.Serialization.DataMemberAttribute"/> are serialized.
This member serialization mode can also be set by marking the class with <see cref="T:System.Runtime.Serialization.DataContractAttribute"/>.
</summary>
</member>