mirror of
https://github.com/JustArchiNET/ArchiSteamFarm.git
synced 2025-12-16 06:20:34 +00:00
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:
@@ -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)) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user