SteamUserPermissions revolution

This is needed for defining multiple operators and/or masters, as well as eventual further enhancements
This commit is contained in:
JustArchi
2017-03-15 11:56:20 +01:00
parent 8980667620
commit 39a8d9c8a2
11 changed files with 141 additions and 70 deletions

View File

@@ -62,7 +62,7 @@ namespace ArchiSteamFarm {
internal bool CanReceiveSteamCards => !IsAccountLimited && !IsAccountLocked;
internal bool HasMobileAuthenticator => BotDatabase?.MobileAuthenticator != null;
internal bool IsConnectedAndLoggedOn => (SteamClient?.IsConnected == true) && (SteamClient.SteamID != null);
internal bool IsConnectedAndLoggedOn => SteamID != 0;
internal bool IsPlayingPossible => !PlayingBlocked && (LibraryLockedBySteamID == 0);
[JsonProperty]
@@ -459,12 +459,30 @@ namespace ArchiSteamFarm {
}
}
internal bool IsMaster(ulong steamID) {
if (steamID == 0) {
ArchiLogger.LogNullError(nameof(steamID));
return false;
}
if (IsOwner(steamID)) {
return true;
}
return GetSteamUserPermission(steamID) >= BotConfig.EPermission.Master;
}
internal async Task LootIfNeeded() {
if (!BotConfig.SendOnFarmingFinished || (BotConfig.SteamMasterID == 0) || !IsConnectedAndLoggedOn || (BotConfig.SteamMasterID == SteamClient.SteamID)) {
if (!IsConnectedAndLoggedOn || !BotConfig.SendOnFarmingFinished) {
return;
}
await ResponseLoot(BotConfig.SteamMasterID).ConfigureAwait(false);
ulong steamMasterID = GetFirstSteamMasterID();
if (steamMasterID == 0) {
return;
}
await ResponseLoot(steamMasterID).ConfigureAwait(false);
}
internal async Task OnFarmingFinished(bool farmedSomething) {
@@ -549,7 +567,7 @@ namespace ArchiSteamFarm {
return false;
}
if (await ArchiWebHandler.Init(SteamClient.SteamID, SteamClient.ConnectedUniverse, callback.Nonce, BotConfig.SteamParentalPIN).ConfigureAwait(false)) {
if (await ArchiWebHandler.Init(SteamID, SteamClient.ConnectedUniverse, callback.Nonce, BotConfig.SteamParentalPIN).ConfigureAwait(false)) {
return true;
}
@@ -866,6 +884,18 @@ namespace ArchiSteamFarm {
return result;
}
private ulong GetFirstSteamMasterID() => BotConfig.SteamUserPermissions.Where(kv => (kv.Key != SteamID) && (kv.Value == BotConfig.EPermission.Master)).Select(kv => kv.Key).OrderBy(steamID => steamID).FirstOrDefault();
private BotConfig.EPermission GetSteamUserPermission(ulong steamID) {
if (steamID == 0) {
ArchiLogger.LogNullError(nameof(steamID));
return BotConfig.EPermission.None;
}
BotConfig.EPermission permission;
return BotConfig.SteamUserPermissions.TryGetValue(steamID, out permission) ? permission : BotConfig.EPermission.None;
}
private void HandleCallbacks() {
TimeSpan timeSpan = TimeSpan.FromMilliseconds(CallbackSleep);
while (KeepRunning || SteamClient.IsConnected) {
@@ -1021,24 +1051,29 @@ namespace ArchiSteamFarm {
private void InitModules() {
CardsFarmer.SetInitialState(BotConfig.Paused);
if ((BotConfig.SendTradePeriod > 0) && (BotConfig.SteamMasterID != 0)) {
TimeSpan delay = TimeSpan.FromHours(BotConfig.SendTradePeriod) + TimeSpan.FromMinutes(Bots.Count);
TimeSpan period = TimeSpan.FromHours(BotConfig.SendTradePeriod);
if (SendItemsTimer == null) {
SendItemsTimer = new Timer(
async e => await ResponseLoot(BotConfig.SteamMasterID).ConfigureAwait(false),
null,
delay, // Delay
period // Period
);
} else {
SendItemsTimer.Change(delay, period);
}
} else if (SendItemsTimer != null) {
if (SendItemsTimer != null) {
SendItemsTimer.Dispose();
SendItemsTimer = null;
}
if (BotConfig.SendTradePeriod == 0) {
return;
}
ulong steamMasterID = BotConfig.SteamUserPermissions.Where(kv => kv.Value == BotConfig.EPermission.Master).Select(kv => kv.Key).FirstOrDefault();
if (steamMasterID == 0) {
return;
}
TimeSpan delay = TimeSpan.FromHours(BotConfig.SendTradePeriod) + TimeSpan.FromMinutes(Bots.Count);
TimeSpan period = TimeSpan.FromHours(BotConfig.SendTradePeriod);
SendItemsTimer = new Timer(
async e => await ResponseLoot(steamMasterID).ConfigureAwait(false),
null,
delay, // Delay
period // Period
);
}
private void InitPermanentConnectionFailure() {
@@ -1061,22 +1096,17 @@ namespace ArchiSteamFarm {
await Start().ConfigureAwait(false);
}
private bool IsMaster(ulong steamID) {
if (steamID != 0) {
return (steamID == BotConfig.SteamMasterID) || IsOwner(steamID);
private bool IsFamilySharing(ulong steamID) {
if (steamID == 0) {
ArchiLogger.LogNullError(nameof(steamID));
return false;
}
ArchiLogger.LogNullError(nameof(steamID));
return false;
}
private bool IsOperator(ulong steamID) {
if (steamID != 0) {
return (steamID == BotConfig.SteamOperatorID) || IsMaster(steamID);
if (IsOwner(steamID)) {
return true;
}
ArchiLogger.LogNullError(nameof(steamID));
return false;
return SteamFamilySharingIDs.Contains(steamID) || (GetSteamUserPermission(steamID) >= BotConfig.EPermission.FamilySharing);
}
private bool IsMasterClanID(ulong steamID) {
@@ -1088,6 +1118,19 @@ namespace ArchiSteamFarm {
return false;
}
private bool IsOperator(ulong steamID) {
if (steamID == 0) {
ArchiLogger.LogNullError(nameof(steamID));
return false;
}
if (IsOwner(steamID)) {
return true;
}
return GetSteamUserPermission(steamID) >= BotConfig.EPermission.Operator;
}
private static bool IsOwner(ulong steamID) {
if (steamID != 0) {
return (steamID == Program.GlobalConfig.SteamOwnerID) || (Debugging.IsDebugBuild && (steamID == SharedInfo.ArchiSteamID));
@@ -1706,7 +1749,7 @@ namespace ArchiSteamFarm {
return;
}
if (callback.FriendID == SteamClient.SteamID) {
if (callback.FriendID == SteamID) {
Events.OnPersonaState(this, callback);
Statistics?.OnPersonaState(callback).Forget();
} else if ((callback.FriendID == LibraryLockedBySteamID) && (callback.GameID == 0)) {
@@ -1749,13 +1792,13 @@ namespace ArchiSteamFarm {
// Ignore no status updates
if (LibraryLockedBySteamID == 0) {
if ((callback.LibraryLockedBySteamID == 0) || (callback.LibraryLockedBySteamID == SteamClient.SteamID)) {
if ((callback.LibraryLockedBySteamID == 0) || (callback.LibraryLockedBySteamID == SteamID)) {
return;
}
LibraryLockedBySteamID = callback.LibraryLockedBySteamID;
} else {
if ((callback.LibraryLockedBySteamID != 0) && (callback.LibraryLockedBySteamID != SteamClient.SteamID)) {
if ((callback.LibraryLockedBySteamID != 0) && (callback.LibraryLockedBySteamID != SteamID)) {
return;
}
@@ -2096,7 +2139,7 @@ namespace ArchiSteamFarm {
private string ResponseHelp(ulong steamID) {
if (steamID != 0) {
return IsOperator(steamID) ? FormatBotResponse("https://github.com/" + SharedInfo.GithubRepo + "/wiki/Commands") : null;
return IsFamilySharing(steamID) ? FormatBotResponse("https://github.com/" + SharedInfo.GithubRepo + "/wiki/Commands") : null;
}
ArchiLogger.LogNullError(nameof(steamID));
@@ -2175,11 +2218,12 @@ namespace ArchiSteamFarm {
return FormatBotResponse(Strings.BotLootingTemporarilyDisabled);
}
if (BotConfig.SteamMasterID == 0) {
ulong targetSteamMasterID = GetFirstSteamMasterID();
if (targetSteamMasterID == 0) {
return FormatBotResponse(Strings.BotLootingMasterNotDefined);
}
if (BotConfig.SteamMasterID == SteamClient.SteamID) {
if (targetSteamMasterID == SteamID) {
return FormatBotResponse(Strings.BotLootingYourself);
}
@@ -2198,12 +2242,12 @@ namespace ArchiSteamFarm {
return FormatBotResponse(Strings.BotLootingFailed);
}
if (!await ArchiWebHandler.SendTradeOffer(inventory, BotConfig.SteamMasterID, BotConfig.SteamTradeToken).ConfigureAwait(false)) {
if (!await ArchiWebHandler.SendTradeOffer(inventory, targetSteamMasterID, BotConfig.SteamTradeToken).ConfigureAwait(false)) {
return FormatBotResponse(Strings.BotLootingFailed);
}
await Task.Delay(3000).ConfigureAwait(false); // Sometimes we can be too fast for Steam servers to generate confirmations, wait a short moment
await AcceptConfirmations(true, Steam.ConfirmationDetails.EType.Trade, BotConfig.SteamMasterID).ConfigureAwait(false);
await AcceptConfirmations(true, Steam.ConfirmationDetails.EType.Trade, targetSteamMasterID).ConfigureAwait(false);
return FormatBotResponse(Strings.BotLootingSuccess);
}
@@ -2299,7 +2343,7 @@ namespace ArchiSteamFarm {
Dictionary<uint, string> ownedGames;
if (await ArchiWebHandler.HasValidApiKey().ConfigureAwait(false)) {
ownedGames = await ArchiWebHandler.GetOwnedGames(SteamClient.SteamID).ConfigureAwait(false);
ownedGames = await ArchiWebHandler.GetOwnedGames(SteamID).ConfigureAwait(false);
} else {
ownedGames = await ArchiWebHandler.GetMyOwnedGames().ConfigureAwait(false);
}
@@ -2423,10 +2467,13 @@ namespace ArchiSteamFarm {
return null;
}
if (!IsMaster(steamID)) {
if (sticky || !SteamFamilySharingIDs.Contains(steamID)) {
return null;
}
BotConfig.EPermission permission = GetSteamUserPermission(steamID);
if (permission < BotConfig.EPermission.FamilySharing) {
return null;
}
if (sticky && (permission < BotConfig.EPermission.Master)) {
return FormatBotResponse(Strings.ErrorAccessDenied);
}
if (!IsConnectedAndLoggedOn) {
@@ -2439,7 +2486,7 @@ namespace ArchiSteamFarm {
await CardsFarmer.Pause(sticky).ConfigureAwait(false);
if (!SteamFamilySharingIDs.Contains(steamID)) {
if (permission >= BotConfig.EPermission.Master) {
return FormatBotResponse(Strings.BotAutomaticIdlingNowPaused);
}
@@ -2913,7 +2960,7 @@ namespace ArchiSteamFarm {
return null;
}
if (!IsOperator(steamID)) {
if (!IsFamilySharing(steamID)) {
return null;
}

View File

@@ -97,15 +97,13 @@ namespace ArchiSteamFarm {
[JsonProperty(Required = Required.DisallowNull)]
internal readonly ulong SteamMasterClanID = 0;
[JsonProperty(Required = Required.DisallowNull)]
internal readonly ulong SteamMasterID = 0;
[JsonProperty(Required = Required.DisallowNull)]
internal readonly ulong SteamOperatorID = 0;
[JsonProperty]
internal readonly string SteamTradeToken = null;
[SuppressMessage("ReSharper", "CollectionNeverUpdated.Global")]
[JsonProperty(Required = Required.DisallowNull)]
internal readonly Dictionary<ulong, EPermission> SteamUserPermissions = new Dictionary<ulong, EPermission>();
[JsonProperty(Required = Required.DisallowNull)]
internal readonly ETradingPreferences TradingPreferences = ETradingPreferences.None;
@@ -178,6 +176,13 @@ namespace ArchiSteamFarm {
NamesDescending
}
internal enum EPermission : byte {
None,
FamilySharing,
Operator,
Master
}
[Flags]
internal enum ERedeemingPreferences : byte {
None = 0,

View File

@@ -376,7 +376,7 @@ namespace ArchiSteamFarm.Localization {
}
/// <summary>
/// Wyszukuje zlokalizowany ciąg podobny do ciągu Trade couldn&apos;t be sent because SteamMasterID is not defined!.
/// Wyszukuje zlokalizowany ciąg podobny do ciągu Trade couldn&apos;t be sent because there is no master user defined!.
/// </summary>
internal static string BotLootingMasterNotDefined {
get {
@@ -718,6 +718,15 @@ namespace ArchiSteamFarm.Localization {
}
}
/// <summary>
/// Wyszukuje zlokalizowany ciąg podobny do ciągu Access denied!.
/// </summary>
internal static string ErrorAccessDenied {
get {
return ResourceManager.GetString("ErrorAccessDenied", resourceCulture);
}
}
/// <summary>
/// Wyszukuje zlokalizowany ciąg podobny do ciągu Your bot config is invalid. Please verify content of {0} and try again!.
/// </summary>

View File

@@ -549,7 +549,7 @@ StackTrace:
<value>Trade offer failed!</value>
</data>
<data name="BotLootingMasterNotDefined" xml:space="preserve">
<value>Trade couldn't be sent because SteamMasterID is not defined!</value>
<value>Trade couldn't be sent because there is no master user defined!</value>
<comment>SteamMasterID is name of bot config property, it should not be translated</comment>
</data>
<data name="BotLootingNoLootableTypes" xml:space="preserve">
@@ -714,4 +714,7 @@ StackTrace:
<value>Owned already: {0}</value>
<comment>{0} will be replaced by game's ID (number), {1} will be replaced by game's name</comment>
</data>
<data name="ErrorAccessDenied" xml:space="preserve">
<value>Access denied!</value>
</data>
</root>

View File

@@ -178,7 +178,7 @@ namespace ArchiSteamFarm {
}
// Always accept trades from SteamMasterID
if ((tradeOffer.OtherSteamID64 != 0) && ((tradeOffer.OtherSteamID64 == Bot.BotConfig.SteamMasterID) || (tradeOffer.OtherSteamID64 == Program.GlobalConfig.SteamOwnerID))) {
if ((tradeOffer.OtherSteamID64 != 0) && Bot.IsMaster(tradeOffer.OtherSteamID64)) {
return new ParseTradeResult(tradeOffer.TradeOfferID, tradeOffer.ItemsToGive.Count > 0 ? ParseTradeResult.EResult.AcceptedWithItemLose : ParseTradeResult.EResult.AcceptedWithoutItemLose);
}

View File

@@ -23,10 +23,9 @@
"ShutdownOnFarmingFinished": false,
"SteamLogin": null,
"SteamMasterClanID": 0,
"SteamMasterID": 0,
"SteamOperatorID": 0,
"SteamParentalPIN": "0",
"SteamPassword": null,
"SteamTradeToken": null,
"SteamUserPermissions": {},
"TradingPreferences": 0
}

View File

@@ -30,6 +30,7 @@ using System.Drawing.Design;
using System.IO;
using ConfigGenerator.JSON;
using Newtonsoft.Json;
using Wexman.Design;
namespace ConfigGenerator {
[SuppressMessage("ReSharper", "AutoPropertyCanBeMadeGetOnly.Global")]
@@ -112,14 +113,6 @@ namespace ConfigGenerator {
[JsonProperty(Required = Required.DisallowNull)]
public ulong SteamMasterClanID { get; set; } = 0;
[LocalizedCategory("Access")]
[JsonProperty(Required = Required.DisallowNull)]
public ulong SteamMasterID { get; set; } = 0;
[LocalizedCategory("Access")]
[JsonProperty(Required = Required.DisallowNull)]
public ulong SteamOperatorID { get; set; } = 0;
[LocalizedCategory("Access")]
[JsonProperty]
public string SteamParentalPIN { get; set; } = "0";
@@ -133,6 +126,11 @@ namespace ConfigGenerator {
[JsonProperty]
public string SteamTradeToken { get; set; } = null;
[LocalizedCategory("Access")]
[Editor(typeof(GenericDictionaryEditor<ulong, EPermission>), typeof(UITypeEditor))]
[JsonProperty(Required = Required.DisallowNull)]
public Dictionary<ulong, EPermission> SteamUserPermissions { get; set; } = new Dictionary<ulong, EPermission>();
[LocalizedCategory("Advanced")]
[Editor(typeof(FlagEnumUiEditor), typeof(UITypeEditor))]
[JsonProperty(Required = Required.DisallowNull)]
@@ -195,6 +193,13 @@ namespace ConfigGenerator {
NamesDescending
}
internal enum EPermission : byte {
None,
FamilySharing,
Operator,
Master
}
[Flags]
internal enum ERedeemingPreferences : byte {
None = 0,

View File

@@ -46,6 +46,9 @@
<RunPostBuildEvent>OnOutputUpdated</RunPostBuildEvent>
</PropertyGroup>
<ItemGroup>
<Reference Include="GenericDictionaryEditor, Version=1.1.0.0, Culture=neutral, PublicKeyToken=7f1cce5280f1f8eb, processorArchitecture=MSIL">
<HintPath>..\packages\GenDictEdit.1.1.0\lib\net20\GenericDictionaryEditor.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.10.0.1-beta1\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>

View File

@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Costura.Fody" version="2.0.0-beta0018" targetFramework="net461" developmentDependency="true" />
<package id="Fody" version="1.30.0-beta01" targetFramework="net461" developmentDependency="true" />
<package id="Newtonsoft.Json" version="10.0.1-beta1" targetFramework="net461" />
<package id="Resource.Embedder" version="1.2.2" targetFramework="net461" developmentDependency="true" />
<package id="Costura.Fody" version="2.0.0-beta0018" targetFramework="net461" developmentDependency="true" />
<package id="Fody" version="1.30.0-beta01" targetFramework="net461" developmentDependency="true" />
<package id="GenDictEdit" version="1.1.0" targetFramework="net461" />
<package id="Newtonsoft.Json" version="10.0.1-beta1" targetFramework="net461" />
<package id="Resource.Embedder" version="1.2.2" targetFramework="net461" developmentDependency="true" />
</packages>

Binary file not shown.

Binary file not shown.