Enhance !addlicense command

We can actually provide very limited details about license activation with the newly implemented endpoint. While this won't provide valuable feedback for vast majority of cases, it can at least pretty reliably provide Fail/RateLimited, for example.

Huge thanks to @xPaw for the discovery and help
This commit is contained in:
Archi
2021-09-27 19:50:18 +02:00
parent e79f41be42
commit de19010820
3 changed files with 39 additions and 13 deletions

View File

@@ -178,6 +178,9 @@ namespace ArchiSteamFarm.Core {
[PublicAPI]
public static bool IsServerErrorCode(this HttpStatusCode statusCode) => statusCode is >= HttpStatusCode.InternalServerError and < (HttpStatusCode) 600;
[PublicAPI]
public static bool IsSuccessCode(this HttpStatusCode statusCode) => statusCode is >= HttpStatusCode.OK and < HttpStatusCode.Ambiguous;
[PublicAPI]
public static bool IsValidCdKey(string key) {
if (string.IsNullOrEmpty(key)) {

View File

@@ -1295,22 +1295,49 @@ namespace ArchiSteamFarm.Steam.Integration {
return response != null ? (true, response.Content.RequiresMobileConfirmation) : (false, false);
}
internal async Task<bool> AddFreeLicense(uint subID) {
internal async Task<(EResult Result, EPurchaseResultDetail PurchaseResult)> AddFreeLicense(uint subID) {
if (subID == 0) {
throw new ArgumentOutOfRangeException(nameof(subID));
}
Uri request = new(SteamStoreURL, "/checkout/addfreelicense");
Uri request = new(SteamStoreURL, $"/checkout/addfreelicense/{subID}");
// Extra entry for sessionID
Dictionary<string, string> data = new(3, StringComparer.Ordinal) {
{ "action", "add_to_cart" },
{ "subid", subID.ToString(CultureInfo.InvariantCulture) }
Dictionary<string, string> data = new(2, StringComparer.Ordinal) {
{ "ajax", "true" }
};
using HtmlDocumentResponse? response = await UrlPostToHtmlDocumentWithSession(request, data: data).ConfigureAwait(false);
ObjectResponse<JToken>? response = await UrlPostToJsonObjectWithSession<JToken>(request, data: data, requestOptions: WebBrowser.ERequestOptions.ReturnClientErrors | WebBrowser.ERequestOptions.ReturnServerErrors).ConfigureAwait(false);
return response?.Content.SelectSingleNode("//div[@class='add_free_content_success_area']") != null;
if (response == null) {
return (EResult.Fail, EPurchaseResultDetail.Timeout);
}
switch (response.StatusCode) {
case HttpStatusCode.Forbidden:
// Let's convert this into something reasonable
return (EResult.AccessDenied, EPurchaseResultDetail.InvalidPackage);
case HttpStatusCode.InternalServerError:
case HttpStatusCode.OK:
// This API is total nuts, it returns sometimes [ ], sometimes { "purchaseresultdetail": int } and sometimes null because f**k you, that's why, I wouldn't be surprised if it returned XML one day
// There is not much we can do apart from trying to extract the result and returning it along with the OK and non-OK response, it's also why it doesn't make any sense to strong-type it
EPurchaseResultDetail purchaseResult = EPurchaseResultDetail.NoDetail;
if (response.Content is JObject jObject) {
byte? numberResult = jObject["purchaseresultdetail"]?.Value<byte>();
if (numberResult.HasValue) {
purchaseResult = (EPurchaseResultDetail) numberResult.Value;
}
}
return (response.StatusCode.IsSuccessCode() ? EResult.OK : EResult.Fail, purchaseResult);
default:
// We should handle all expected status codes above, this is a generic fallback for those that we don't
Bot.ArchiLogger.LogGenericError(string.Format(CultureInfo.CurrentCulture, Strings.WarningUnknownValuePleaseReport, nameof(response.StatusCode), response.StatusCode));
return (response.StatusCode.IsSuccessCode() ? EResult.OK : EResult.Fail, EPurchaseResultDetail.ContactSupport);
}
}
internal async Task<bool> ChangePrivacySettings(UserPrivacy userPrivacy) {

View File

@@ -647,13 +647,9 @@ namespace ArchiSteamFarm.Steam.Interaction {
break;
default:
if (!await Bot.ArchiWebHandler.AddFreeLicense(gameID).ConfigureAwait(false)) {
response.AppendLine(FormatBotResponse(string.Format(CultureInfo.CurrentCulture, Strings.BotAddLicense, "sub/" + gameID, EResult.Fail)));
(EResult result, EPurchaseResultDetail purchaseResult) = await Bot.ArchiWebHandler.AddFreeLicense(gameID).ConfigureAwait(false);
continue;
}
response.AppendLine(FormatBotResponse(string.Format(CultureInfo.CurrentCulture, Strings.BotAddLicenseWithItems, gameID, EResult.OK, "sub/" + gameID)));
response.AppendLine(FormatBotResponse(string.Format(CultureInfo.CurrentCulture, Strings.BotAddLicense, "sub/" + gameID, result + "/" + purchaseResult)));
break;
}