diff --git a/KfChatDotNetBot/Services/BotServices.cs b/KfChatDotNetBot/Services/BotServices.cs index ba72e09..bee7c6a 100644 --- a/KfChatDotNetBot/Services/BotServices.cs +++ b/KfChatDotNetBot/Services/BotServices.cs @@ -963,7 +963,8 @@ public class BotServices .GetMultipleValuesAsync([ BuiltIn.Keys.ShuffleBmjUsername, BuiltIn.Keys.ShuffleDotUsBmjUsername, BuiltIn.Keys.KiwiFarmsGreenColor, BuiltIn.Keys.KiwiFarmsRedColor, - BuiltIn.Keys.ShuffleBmjUserId, BuiltIn.Keys.ShuffleBmjVipLevel + BuiltIn.Keys.ShuffleBmjUserId, BuiltIn.Keys.ShuffleBmjVipLevel, + BuiltIn.Keys.ShuffleDotUsBmjUserId, BuiltIn.Keys.ShuffleDotUsBmjVipLevel ]).Result; _logger.Trace("Shuffle bet has arrived"); bool offlineBet = false; @@ -991,6 +992,30 @@ public class BotServices if (betOwner != settings[BuiltIn.Keys.ShuffleBmjUserId].Value) return; offlineBet = true; } + if (bet.Username == null && bet.VipLevel == settings[BuiltIn.Keys.ShuffleDotUsBmjVipLevel].Value && !CheckBmjIsLive().Result && isDotUs) + { + _logger.Info($"Checking for potential Shuffle.us offline bet {bet.Id}"); + string? betOwner; + try + { + betOwner = _shuffleDotUs?.GetBetUser(bet.Id).Result; + } + catch (Exception e) + { + _logger.Error($"Caught an error when trying to get {bet.Id}"); + _logger.Error(e); + return; + } + if (betOwner == null) + { + _logger.Error($"Failed to get the bet owner for {bet.Id}"); + return; + } + _logger.Info($"Got user ID {betOwner}"); + + if (betOwner != settings[BuiltIn.Keys.ShuffleDotUsBmjUserId].Value) return; + offlineBet = true; + } if (bet.Username == settings[BuiltIn.Keys.ShuffleBmjUsername].Value) { UpdateBossmanLastSighting($"betting {bet.Amount} {bet.Currency} on {bet.GameName} at Shuffle.com").Wait(_cancellationToken); @@ -999,14 +1024,20 @@ public class BotServices { UpdateBossmanLastSighting($"betting {bet.Amount} {bet.Currency} on {bet.GameName} at Shuffle.us").Wait(_cancellationToken); } - else if (offlineBet) + else if (offlineBet && !isDotUs) { UpdateBossmanLastSighting($"betting {bet.Amount} {bet.Currency} on {bet.GameName} at Shuffle.com OFFLINE").Wait(_cancellationToken); } + else if (offlineBet && isDotUs) + { + UpdateBossmanLastSighting($"betting {bet.Amount} {bet.Currency} on {bet.GameName} at Shuffle.us OFFLINE").Wait(_cancellationToken); + } else { return; } + + if (offlineBet) bet.Username = "OFFLINE GAMBLING NIGGER"; _logger.Info($"ALERT BMJ IS BETTING: isDotUs => {isDotUs}"); if (CheckBmjIsLive().Result) return; diff --git a/KfChatDotNetBot/Services/ShuffleDotUs.cs b/KfChatDotNetBot/Services/ShuffleDotUs.cs index c0c8c61..c7a0a76 100644 --- a/KfChatDotNetBot/Services/ShuffleDotUs.cs +++ b/KfChatDotNetBot/Services/ShuffleDotUs.cs @@ -1,4 +1,5 @@ using System.Net; +using System.Net.Http.Headers; using System.Net.Http.Json; using System.Net.WebSockets; using System.Text.Json; @@ -163,6 +164,58 @@ public class ShuffleDotUs : IDisposable _logger.Error("--- End of JSON Payload ---"); } } + + public async Task GetBetUser(string betId) + { + var gql = "query GetBetInfo($betId: String!) {\n bet(id: $betId) {\n id\n completedAt\n account {\n id\n user {\n username\n vipLevel\n __typename\n }\n __typename\n }\n game {\n id\n name\n slug\n edge\n accentColor\n image {\n key\n __typename\n }\n gameAndGameCategories {\n gameCategoryName\n gameId\n main\n __typename\n }\n provider {\n id\n name\n __typename\n }\n originalGame\n __typename\n }\n gameSeed {\n ...GameSeedFields\n __typename\n }\n gameSeedNonce\n shuffleOriginalActions {\n id\n updatedAt\n createdAt\n action {\n dice {\n ...DiceFields\n __typename\n }\n plinko {\n multiplier\n results\n risk\n rows\n __typename\n }\n mines {\n minesResult\n minesCount\n winMultiplier\n selected\n __typename\n }\n limbo {\n resultRaw\n resultValue\n userValue\n __typename\n }\n keno {\n results\n risk\n multiplier\n selected\n __typename\n }\n hilo {\n card\n guess\n winMultiplier\n actionType\n __typename\n }\n blackjack {\n mainPlayerHand\n mainPlayerActions\n splitPlayerHand\n splitPlayerActions\n dealerHand\n perfectPairWin\n twentyOnePlusThreeWin\n twentyOnePlusThreeAmount\n perfectPairAmount\n insuranceStatus\n originalMainBetAmount\n mainHandOutcome\n splitHandOutcome\n __typename\n }\n roulette {\n resultRaw\n resultValue\n userInput {\n parityValues {\n amount\n parity\n __typename\n }\n colorValues {\n amount\n color\n __typename\n }\n halfValues {\n amount\n half\n __typename\n }\n columnValues {\n amount\n column\n __typename\n }\n dozenValues {\n amount\n dozen\n __typename\n }\n straightValues {\n amount\n straightNumber\n __typename\n }\n splitValues {\n amount\n firstNumber\n secondNumber\n __typename\n }\n streetValues {\n amount\n street\n __typename\n }\n cornerValues {\n amount\n firstNumber\n secondNumber\n thirdNumber\n fourthNumber\n __typename\n }\n doubleStreetValues {\n amount\n firstStreet\n secondStreet\n __typename\n }\n __typename\n }\n __typename\n }\n wheel {\n resultRaw\n resultSegment\n risk\n segments\n __typename\n }\n tower {\n towerResult\n towerDifficulty\n winMultiplier\n selected\n __typename\n }\n chicken {\n chickenResult\n chickenDifficulty\n winMultiplier\n selectedLane\n __typename\n }\n __typename\n }\n __typename\n }\n amount\n originalAmount\n payout\n currency\n usdRate\n createdAt\n afterBalance\n multiplier\n replayUrl\n __typename\n }\n}\n\nfragment GameSeedFields on GameSeed {\n id\n clientSeed\n seed\n hashedSeed\n status\n currentNonce\n createdAt\n __typename\n}\n\nfragment DiceFields on DiceActionModel {\n userDiceDirection\n userValue\n resultValue\n resultRaw\n __typename\n}"; + _logger.Debug($"Grabbing details for Shuffle bet {betId}"); + var jsonBody = new Dictionary + { + { "operationName", "GetBetInfo" }, + { "query", gql }, + { "variables", new Dictionary { { "betId", betId } } }, + { "extensions", new Dictionary> { + { + "clientLibrary", new Dictionary() + { + {"name", "@apollo/client"}, + {"version", "4.1.4"} + } + } } }, + }; + _logger.Debug("Created dictionary object for the JSON payload, should serialize to following value:"); + _logger.Debug(JsonSerializer.Serialize(jsonBody)); + var handler = new HttpClientHandler { AutomaticDecompression = DecompressionMethods.All }; + if (_proxy != null) + { + handler.UseProxy = false; + handler.Proxy = new WebProxy(_proxy); + _logger.Debug($"Configured to use proxy {_proxy}"); + } + using var client = new HttpClient(handler); + client.DefaultRequestHeaders.Referrer = new Uri($"https://shuffle.us/?md-id={betId}&modal=bet"); + client.DefaultRequestHeaders.TryAddWithoutValidation("Origin", "https://shuffle.us"); + client.DefaultRequestHeaders.UserAgent.Clear(); + client.DefaultRequestHeaders.UserAgent.TryParseAdd("Mozilla/5.0 (X11; Linux x86_64; rv:147.0) Gecko/20100101 Firefox/147.0"); + client.DefaultRequestHeaders.AcceptLanguage.Clear(); + client.DefaultRequestHeaders.AcceptLanguage.TryParseAdd("en-US"); + client.DefaultRequestHeaders.Accept.Clear(); + client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/graphql-response+json")); + client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); + var postBody = JsonContent.Create(jsonBody, new MediaTypeWithQualityHeaderValue("application/json")); + var response = await client.PostAsync("https://shuffle.us/main-api/graphql/api/graphql", postBody, _cancellationToken); + var responseContent = await response.Content.ReadFromJsonAsync(cancellationToken: _cancellationToken); + _logger.Debug("Shuffle returned following JSON"); + _logger.Debug(responseContent.GetRawText); + var user = responseContent.GetProperty("data").GetProperty("bet").GetProperty("account").GetProperty("id"); + if (user.ValueKind == JsonValueKind.Null) + { + _logger.Debug("user was null"); + throw new ShuffleUserNotFoundException(); + } + + return user.GetString() ?? throw new InvalidOperationException(); + } public async Task GetShuffleUser(string username) { diff --git a/KfChatDotNetBot/Settings/BuiltIn.cs b/KfChatDotNetBot/Settings/BuiltIn.cs index edf7686..a4e4c24 100644 --- a/KfChatDotNetBot/Settings/BuiltIn.cs +++ b/KfChatDotNetBot/Settings/BuiltIn.cs @@ -560,6 +560,10 @@ public static class BuiltIn public static string ShuffleBmjVipLevel = "Shuffle.BmjVipLevel"; [BuiltInSetting("Whether OpenAI moderation is enabled", SettingValueType.Boolean, "false", BooleanRegex)] public static string OpenAiModerationEnabled = "OpenAI.ModerationEnabled"; + [BuiltInSetting("Bossman's current VIP level on .us for reducing GraphQL hits", SettingValueType.Text, "PLATINUM_1")] + public static string ShuffleDotUsBmjVipLevel = "ShuffleDotUs.BmjVipLevel"; + [BuiltInSetting("Bossman's super secret user ID on .us", SettingValueType.Text, "e2faee09-8ebb-4a22-8793-59aefc8191e5")] + public static string ShuffleDotUsBmjUserId = "ShuffleDotUs.BmjUserId"; } }