From bde722b382cc8958f44ea1efe314cd2f7107e036 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20=C5=81abno?= Date: Tue, 19 May 2026 13:03:34 +0200 Subject: [PATCH 1/4] Update RestSharp, mitigate CVE-2024-45302 --- csharp-smsapi.sln | 1 + smsapi/Api/Action/Base.cs | 16 +++++++++-- .../Api/Action/Contacts/BindContactToGroup.cs | 2 +- smsapi/Api/Action/Contacts/ContactsBase.cs | 7 +++++ smsapi/Api/Action/Contacts/CreateContact.cs | 2 +- smsapi/Api/Action/Contacts/CreateField.cs | 2 +- smsapi/Api/Action/Contacts/CreateGroup.cs | 2 +- .../Action/Contacts/CreateGroupPermission.cs | 2 +- smsapi/Api/Action/Contacts/DeleteContact.cs | 2 +- smsapi/Api/Action/Contacts/DeleteField.cs | 2 +- smsapi/Api/Action/Contacts/DeleteGroup.cs | 2 +- .../Action/Contacts/DeleteGroupPermission.cs | 2 +- smsapi/Api/Action/Contacts/EditContact.cs | 2 +- smsapi/Api/Action/Contacts/EditField.cs | 2 +- smsapi/Api/Action/Contacts/EditGroup.cs | 2 +- .../Action/Contacts/EditGroupPermission.cs | 2 +- smsapi/Api/Action/Contacts/GetContact.cs | 2 +- smsapi/Api/Action/Contacts/GetContactGroup.cs | 2 +- smsapi/Api/Action/Contacts/GetGroup.cs | 2 +- .../Api/Action/Contacts/GetGroupPermission.cs | 2 +- .../Api/Action/Contacts/ListContactGroups.cs | 2 +- smsapi/Api/Action/Contacts/ListContacts.cs | 2 +- .../Api/Action/Contacts/ListFieldOptions.cs | 2 +- smsapi/Api/Action/Contacts/ListFields.cs | 2 +- .../Action/Contacts/ListGroupPermissions.cs | 2 +- smsapi/Api/Action/Contacts/ListGroups.cs | 2 +- .../Action/Contacts/UnbindContactFromGroup.cs | 2 +- smsapi/Properties/AssemblyInfo.cs | 4 +-- smsapi/ProxyHTTP.cs | 28 ++++++++----------- smsapi/smsapi.csproj | 4 +-- smsapiTests/ConfigurationTest.cs | 15 +++++----- smsapiTests/MmsTest.cs | 4 +-- smsapiTests/TestBase.cs | 15 +++++----- smsapiTests/TestConfig.cs | 26 +++++++++++++++++ smsapiTests/VmsTest.cs | 4 +-- smsapiTests/smsapiTests.csproj | 9 +++--- 36 files changed, 110 insertions(+), 71 deletions(-) create mode 100644 smsapi/Api/Action/Contacts/ContactsBase.cs create mode 100644 smsapiTests/TestConfig.cs diff --git a/csharp-smsapi.sln b/csharp-smsapi.sln index 06e0fce..07cc686 100644 --- a/csharp-smsapi.sln +++ b/csharp-smsapi.sln @@ -38,6 +38,7 @@ Global {A0C118D0-9435-477B-92B5-0918E1CDADAF}.Release|Mixed Platforms.Build.0 = Release|Any CPU {A0C118D0-9435-477B-92B5-0918E1CDADAF}.Release|x86.ActiveCfg = Release|Any CPU {A0C118D0-9435-477B-92B5-0918E1CDADAF}.Release|x86.Build.0 = Release|Any CPU + {A0C118D0-9435-477B-92B5-0918E1CDADAF}.Debug|Any CPU.Build.0 = Debug|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/smsapi/Api/Action/Base.cs b/smsapi/Api/Action/Base.cs index 91bbba5..cd39581 100644 --- a/smsapi/Api/Action/Base.cs +++ b/smsapi/Api/Action/Base.cs @@ -16,6 +16,8 @@ public abstract class Base protected abstract RequestMethod Method { get; } + protected virtual bool IncludeJsonFormatParameter => true; + public T Execute() { Validate(); @@ -100,9 +102,17 @@ private T ProcessResponse(Stream data) private NameValueCollection GetValues() { var values = Values(); - return values.Count > 0 - ? new NameValueCollection { { "format", "json" }, values } - : HttpUtility.ParseQueryString(string.Empty); + if (values.Count == 0) + { + return HttpUtility.ParseQueryString(string.Empty); + } + + if (!IncludeJsonFormatParameter) + { + return values; + } + + return new NameValueCollection { { "format", "json" }, values }; } /** diff --git a/smsapi/Api/Action/Contacts/BindContactToGroup.cs b/smsapi/Api/Action/Contacts/BindContactToGroup.cs index 07995ca..76781d9 100644 --- a/smsapi/Api/Action/Contacts/BindContactToGroup.cs +++ b/smsapi/Api/Action/Contacts/BindContactToGroup.cs @@ -3,7 +3,7 @@ namespace SMSApi.Api.Action { - public class BindContactToGroup : Base + public class BindContactToGroup : ContactsBase { private readonly string contactId; private readonly string groupId; diff --git a/smsapi/Api/Action/Contacts/ContactsBase.cs b/smsapi/Api/Action/Contacts/ContactsBase.cs new file mode 100644 index 0000000..bcb5435 --- /dev/null +++ b/smsapi/Api/Action/Contacts/ContactsBase.cs @@ -0,0 +1,7 @@ +namespace SMSApi.Api.Action +{ + public abstract class ContactsBase : Base + { + protected override bool IncludeJsonFormatParameter => false; + } +} diff --git a/smsapi/Api/Action/Contacts/CreateContact.cs b/smsapi/Api/Action/Contacts/CreateContact.cs index 6605ec2..f6518cd 100644 --- a/smsapi/Api/Action/Contacts/CreateContact.cs +++ b/smsapi/Api/Action/Contacts/CreateContact.cs @@ -4,7 +4,7 @@ namespace SMSApi.Api.Action { - public class CreateContact : Base + public class CreateContact : ContactsBase { private DateTime? birthdayDate; private string city; diff --git a/smsapi/Api/Action/Contacts/CreateField.cs b/smsapi/Api/Action/Contacts/CreateField.cs index 698a270..82927e9 100644 --- a/smsapi/Api/Action/Contacts/CreateField.cs +++ b/smsapi/Api/Action/Contacts/CreateField.cs @@ -3,7 +3,7 @@ namespace SMSApi.Api.Action { - public class CreateField : Base + public class CreateField : ContactsBase { private string name; private string type; diff --git a/smsapi/Api/Action/Contacts/CreateGroup.cs b/smsapi/Api/Action/Contacts/CreateGroup.cs index 1a82e0f..524bde8 100644 --- a/smsapi/Api/Action/Contacts/CreateGroup.cs +++ b/smsapi/Api/Action/Contacts/CreateGroup.cs @@ -3,7 +3,7 @@ namespace SMSApi.Api.Action { - public class CreateGroup : Base + public class CreateGroup : ContactsBase { private string description; private string idx; diff --git a/smsapi/Api/Action/Contacts/CreateGroupPermission.cs b/smsapi/Api/Action/Contacts/CreateGroupPermission.cs index d185532..dd5a80b 100644 --- a/smsapi/Api/Action/Contacts/CreateGroupPermission.cs +++ b/smsapi/Api/Action/Contacts/CreateGroupPermission.cs @@ -4,7 +4,7 @@ namespace SMSApi.Api.Action { - public class CreateGroupPermission : Base + public class CreateGroupPermission : ContactsBase { private string groupId; private bool read; diff --git a/smsapi/Api/Action/Contacts/DeleteContact.cs b/smsapi/Api/Action/Contacts/DeleteContact.cs index 0653ecf..5608abf 100644 --- a/smsapi/Api/Action/Contacts/DeleteContact.cs +++ b/smsapi/Api/Action/Contacts/DeleteContact.cs @@ -3,7 +3,7 @@ namespace SMSApi.Api.Action { - public class DeleteContact : Base + public class DeleteContact : ContactsBase { private readonly string contactId; diff --git a/smsapi/Api/Action/Contacts/DeleteField.cs b/smsapi/Api/Action/Contacts/DeleteField.cs index f58aec5..f2f8d12 100644 --- a/smsapi/Api/Action/Contacts/DeleteField.cs +++ b/smsapi/Api/Action/Contacts/DeleteField.cs @@ -3,7 +3,7 @@ namespace SMSApi.Api.Action { - public class DeleteField : Base + public class DeleteField : ContactsBase { private readonly string fieldId; diff --git a/smsapi/Api/Action/Contacts/DeleteGroup.cs b/smsapi/Api/Action/Contacts/DeleteGroup.cs index 06160de..1464df5 100644 --- a/smsapi/Api/Action/Contacts/DeleteGroup.cs +++ b/smsapi/Api/Action/Contacts/DeleteGroup.cs @@ -3,7 +3,7 @@ namespace SMSApi.Api.Action { - public class DeleteGroup : Base + public class DeleteGroup : ContactsBase { private readonly string groupId; diff --git a/smsapi/Api/Action/Contacts/DeleteGroupPermission.cs b/smsapi/Api/Action/Contacts/DeleteGroupPermission.cs index afe50c8..4e2170b 100644 --- a/smsapi/Api/Action/Contacts/DeleteGroupPermission.cs +++ b/smsapi/Api/Action/Contacts/DeleteGroupPermission.cs @@ -3,7 +3,7 @@ namespace SMSApi.Api.Action { - public class DeleteGroupPermission : Base + public class DeleteGroupPermission : ContactsBase { private readonly string groupId; private readonly string username; diff --git a/smsapi/Api/Action/Contacts/EditContact.cs b/smsapi/Api/Action/Contacts/EditContact.cs index 304dd9b..4d95182 100644 --- a/smsapi/Api/Action/Contacts/EditContact.cs +++ b/smsapi/Api/Action/Contacts/EditContact.cs @@ -4,7 +4,7 @@ namespace SMSApi.Api.Action { - public class EditContact : Base + public class EditContact : ContactsBase { private DateTime? birthdayDate; private string city; diff --git a/smsapi/Api/Action/Contacts/EditField.cs b/smsapi/Api/Action/Contacts/EditField.cs index 5be2a5e..9d030cd 100644 --- a/smsapi/Api/Action/Contacts/EditField.cs +++ b/smsapi/Api/Action/Contacts/EditField.cs @@ -5,7 +5,7 @@ namespace SMSApi.Api.Action { - public class EditField : Base + public class EditField : ContactsBase { private string fieldId; private string name; diff --git a/smsapi/Api/Action/Contacts/EditGroup.cs b/smsapi/Api/Action/Contacts/EditGroup.cs index 8ebe2e8..3105965 100644 --- a/smsapi/Api/Action/Contacts/EditGroup.cs +++ b/smsapi/Api/Action/Contacts/EditGroup.cs @@ -4,7 +4,7 @@ namespace SMSApi.Api.Action { - public class EditGroup : Base + public class EditGroup : ContactsBase { private string description; private string groupId; diff --git a/smsapi/Api/Action/Contacts/EditGroupPermission.cs b/smsapi/Api/Action/Contacts/EditGroupPermission.cs index ad4093b..fc834bc 100644 --- a/smsapi/Api/Action/Contacts/EditGroupPermission.cs +++ b/smsapi/Api/Action/Contacts/EditGroupPermission.cs @@ -4,7 +4,7 @@ namespace SMSApi.Api.Action { - public class EditGroupPermission : Base + public class EditGroupPermission : ContactsBase { private string groupId; private bool read; diff --git a/smsapi/Api/Action/Contacts/GetContact.cs b/smsapi/Api/Action/Contacts/GetContact.cs index d59c749..d27e60c 100644 --- a/smsapi/Api/Action/Contacts/GetContact.cs +++ b/smsapi/Api/Action/Contacts/GetContact.cs @@ -3,7 +3,7 @@ namespace SMSApi.Api.Action { - public class GetContact : Base + public class GetContact : ContactsBase { private readonly string contactId; diff --git a/smsapi/Api/Action/Contacts/GetContactGroup.cs b/smsapi/Api/Action/Contacts/GetContactGroup.cs index 226fe06..c937dba 100644 --- a/smsapi/Api/Action/Contacts/GetContactGroup.cs +++ b/smsapi/Api/Action/Contacts/GetContactGroup.cs @@ -3,7 +3,7 @@ namespace SMSApi.Api.Action { - public class GetContactGroup : Base + public class GetContactGroup : ContactsBase { private readonly string contactId; private readonly string groupId; diff --git a/smsapi/Api/Action/Contacts/GetGroup.cs b/smsapi/Api/Action/Contacts/GetGroup.cs index c17c8d0..2bc56c9 100644 --- a/smsapi/Api/Action/Contacts/GetGroup.cs +++ b/smsapi/Api/Action/Contacts/GetGroup.cs @@ -3,7 +3,7 @@ namespace SMSApi.Api.Action { - public class GetGroup : Base + public class GetGroup : ContactsBase { private string groupId; diff --git a/smsapi/Api/Action/Contacts/GetGroupPermission.cs b/smsapi/Api/Action/Contacts/GetGroupPermission.cs index 6f0bf7c..ba8b5ba 100644 --- a/smsapi/Api/Action/Contacts/GetGroupPermission.cs +++ b/smsapi/Api/Action/Contacts/GetGroupPermission.cs @@ -3,7 +3,7 @@ namespace SMSApi.Api.Action { - public class GetGroupPermission : Base + public class GetGroupPermission : ContactsBase { private readonly string groupId; private readonly string username; diff --git a/smsapi/Api/Action/Contacts/ListContactGroups.cs b/smsapi/Api/Action/Contacts/ListContactGroups.cs index 8cacbaa..b065401 100644 --- a/smsapi/Api/Action/Contacts/ListContactGroups.cs +++ b/smsapi/Api/Action/Contacts/ListContactGroups.cs @@ -2,7 +2,7 @@ namespace SMSApi.Api.Action { - public class ListContactGroups : Base + public class ListContactGroups : ContactsBase { private readonly string contactId; diff --git a/smsapi/Api/Action/Contacts/ListContacts.cs b/smsapi/Api/Action/Contacts/ListContacts.cs index 04ebaf7..e82669d 100644 --- a/smsapi/Api/Action/Contacts/ListContacts.cs +++ b/smsapi/Api/Action/Contacts/ListContacts.cs @@ -4,7 +4,7 @@ namespace SMSApi.Api.Action { - public class ListContacts : Base + public class ListContacts : ContactsBase { private DateTime? birthdayDate; private string email; diff --git a/smsapi/Api/Action/Contacts/ListFieldOptions.cs b/smsapi/Api/Action/Contacts/ListFieldOptions.cs index 621ce0b..e78c6de 100644 --- a/smsapi/Api/Action/Contacts/ListFieldOptions.cs +++ b/smsapi/Api/Action/Contacts/ListFieldOptions.cs @@ -2,7 +2,7 @@ namespace SMSApi.Api.Action { - public class ListFieldOptions : Base + public class ListFieldOptions : ContactsBase { private readonly string fieldId; diff --git a/smsapi/Api/Action/Contacts/ListFields.cs b/smsapi/Api/Action/Contacts/ListFields.cs index fe1c123..98dd0e9 100644 --- a/smsapi/Api/Action/Contacts/ListFields.cs +++ b/smsapi/Api/Action/Contacts/ListFields.cs @@ -2,7 +2,7 @@ namespace SMSApi.Api.Action { - public class ListFields : Base + public class ListFields : ContactsBase { protected override RequestMethod Method => RequestMethod.GET; diff --git a/smsapi/Api/Action/Contacts/ListGroupPermissions.cs b/smsapi/Api/Action/Contacts/ListGroupPermissions.cs index adfef95..9fe49fe 100644 --- a/smsapi/Api/Action/Contacts/ListGroupPermissions.cs +++ b/smsapi/Api/Action/Contacts/ListGroupPermissions.cs @@ -2,7 +2,7 @@ namespace SMSApi.Api.Action { - public class ListGroupPermissions : Base + public class ListGroupPermissions : ContactsBase { private string groupId; diff --git a/smsapi/Api/Action/Contacts/ListGroups.cs b/smsapi/Api/Action/Contacts/ListGroups.cs index b8e2300..22d1a95 100644 --- a/smsapi/Api/Action/Contacts/ListGroups.cs +++ b/smsapi/Api/Action/Contacts/ListGroups.cs @@ -3,7 +3,7 @@ namespace SMSApi.Api.Action { - public class ListGroups : Base + public class ListGroups : ContactsBase { private string id; private string name; diff --git a/smsapi/Api/Action/Contacts/UnbindContactFromGroup.cs b/smsapi/Api/Action/Contacts/UnbindContactFromGroup.cs index 3be2204..e482fba 100644 --- a/smsapi/Api/Action/Contacts/UnbindContactFromGroup.cs +++ b/smsapi/Api/Action/Contacts/UnbindContactFromGroup.cs @@ -3,7 +3,7 @@ namespace SMSApi.Api.Action { - public class UnbindContactFromGroup : Base + public class UnbindContactFromGroup : ContactsBase { private readonly string contactId; private readonly string groupId; diff --git a/smsapi/Properties/AssemblyInfo.cs b/smsapi/Properties/AssemblyInfo.cs index 9537df5..1198896 100644 --- a/smsapi/Properties/AssemblyInfo.cs +++ b/smsapi/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ // 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.2.0.0")] -[assembly: AssemblyFileVersion("2.2.0.0")] +[assembly: AssemblyVersion("2.2.1.0")] +[assembly: AssemblyFileVersion("2.2.1.0")] diff --git a/smsapi/ProxyHTTP.cs b/smsapi/ProxyHTTP.cs index 7ade75e..b3426d2 100644 --- a/smsapi/ProxyHTTP.cs +++ b/smsapi/ProxyHTTP.cs @@ -45,22 +45,20 @@ public Stream Execute( Dictionary files, RequestMethod method) { - var responseStream = new MemoryStream(); ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; RestClient client = CreateClient(); - RestRequest request = CreateRequest(uri, responseStream, data, files, method); + RestRequest request = CreateRequest(uri, data, files, method); try { - client.Execute(request); + var response = client.Execute(request); + return ToStream(response); } catch (System.Exception e) { throw new ProxyException("Failed to get response from " + uri, e); } - - return responseStream; } public async Task ExecuteAsync( @@ -86,39 +84,37 @@ public async Task ExecuteAsync( Dictionary files, RequestMethod method) { - var responseStream = new MemoryStream(); ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; RestClient client = CreateClient(); - RestRequest request = CreateRequest(uri, responseStream, data, files, method); + RestRequest request = CreateRequest(uri, data, files, method); try { - await client.ExecuteAsync(request); + var response = await client.ExecuteAsync(request); + return ToStream(response); } catch (System.Exception e) { throw new ProxyException("Failed to get response from " + uri, e); } + } - return responseStream; + private static Stream ToStream(RestResponse response) + { + var bytes = response.RawBytes ?? Array.Empty(); + return new MemoryStream(bytes, writable: false); } private static RestRequest CreateRequest( string uri, - Stream responseStream, NameValueCollection data, Dictionary files, RequestMethod method) { var request = new RestRequest(uri) { - Method = method.ToMethod(), - ResponseWriter = s => - { - s.CopyTo(responseStream); - return s; - } + Method = method.ToMethod() }; foreach (string key in data.Keys) diff --git a/smsapi/smsapi.csproj b/smsapi/smsapi.csproj index 4828450..6a6954a 100644 --- a/smsapi/smsapi.csproj +++ b/smsapi/smsapi.csproj @@ -19,7 +19,7 @@ SMSAPI.pl - 2.2.0 + 2.2.1 false MIT https://www.smsapi.com @@ -34,7 +34,7 @@ - + diff --git a/smsapiTests/ConfigurationTest.cs b/smsapiTests/ConfigurationTest.cs index 3895dd1..128719a 100644 --- a/smsapiTests/ConfigurationTest.cs +++ b/smsapiTests/ConfigurationTest.cs @@ -1,5 +1,4 @@ using System; -using System.Configuration; using Microsoft.VisualStudio.TestTools.UnitTesting; using SMSApi.Api; @@ -11,30 +10,32 @@ public class ConfigurationTest [TestMethod] public void VerifyConfiguration() { - string authorizationType = ConfigurationManager.AppSettings["authorizationType"]; + var appSettings = TestConfig.AppSettings; + + string authorizationType = appSettings["authorizationType"]; if (authorizationType == AuthorizationType.basic.ToString()) { - string password = ConfigurationManager.AppSettings["password"]; + string password = appSettings["password"]; Assert.IsNotNull(password); Assert.AreNotEqual("", password); } else if (authorizationType == AuthorizationType.oauth.ToString()) { - string token = ConfigurationManager.AppSettings["oauthToken"]; + string token = appSettings["oauthToken"]; Assert.IsNotNull(token); Assert.AreNotEqual("", token); } - string username = ConfigurationManager.AppSettings["username"]; + string username = appSettings["username"]; Assert.IsNotNull(username); Assert.AreNotEqual("", username); - string validTestNumber = ConfigurationManager.AppSettings["validTestNumber"]; + string validTestNumber = appSettings["validTestNumber"]; Assert.IsNotNull(validTestNumber); Assert.AreNotEqual("", validTestNumber); ProxyAddress proxy; - Assert.IsTrue(Enum.TryParse(ConfigurationManager.AppSettings["addressType"], out proxy)); + Assert.IsTrue(Enum.TryParse(appSettings["addressType"], out proxy)); } } } diff --git a/smsapiTests/MmsTest.cs b/smsapiTests/MmsTest.cs index 3462fe5..ace70e3 100644 --- a/smsapiTests/MmsTest.cs +++ b/smsapiTests/MmsTest.cs @@ -28,9 +28,7 @@ public void DeletingSentMessage_EmptyResponse() ids[i] = sendResponse.List[i].ID; } - Countable deletedResponse = _factory.ActionDelete().Ids(ids).Execute(); - - Assert.AreEqual(0, deletedResponse.Count); + Assert.ThrowsException(() => _factory.ActionDelete().Ids(ids).Execute()); } [TestMethod] diff --git a/smsapiTests/TestBase.cs b/smsapiTests/TestBase.cs index 6af675c..70b20b3 100644 --- a/smsapiTests/TestBase.cs +++ b/smsapiTests/TestBase.cs @@ -1,5 +1,4 @@ using System; -using System.Configuration; using Microsoft.VisualStudio.TestTools.UnitTesting; using SMSApi.Api; @@ -15,24 +14,26 @@ public abstract class TestBase [TestInitialize] public virtual void SetUp() { - string authorizationType = ConfigurationManager.AppSettings["authorizationType"]; - _username = ConfigurationManager.AppSettings["username"]; + var appSettings = TestConfig.AppSettings; + + string authorizationType = appSettings["authorizationType"]; + _username = appSettings["username"]; if (authorizationType == AuthorizationType.basic.ToString()) { var basicClient = new Client(_username); - basicClient.SetPasswordHash(ConfigurationManager.AppSettings["password"]); + basicClient.SetPasswordHash(appSettings["password"]); _client = basicClient; } else if (authorizationType == AuthorizationType.oauth.ToString()) { - _client = new ClientOAuth(ConfigurationManager.AppSettings["oauthToken"]); + _client = new ClientOAuth(appSettings["oauthToken"]); } _proxyAddress = (ProxyAddress)Enum.Parse( typeof(ProxyAddress), - ConfigurationManager.AppSettings["addressType"]); - _validTestNumber = ConfigurationManager.AppSettings["validTestNumber"]; + appSettings["addressType"]); + _validTestNumber = appSettings["validTestNumber"]; } } } diff --git a/smsapiTests/TestConfig.cs b/smsapiTests/TestConfig.cs new file mode 100644 index 0000000..3e1059d --- /dev/null +++ b/smsapiTests/TestConfig.cs @@ -0,0 +1,26 @@ +using System.Collections.Specialized; +using System.Configuration; + +namespace smsapiTests +{ + internal static class TestConfig + { + private static readonly NameValueCollection _settings = Load(); + + public static NameValueCollection AppSettings => _settings; + + private static NameValueCollection Load() + { + var assemblyPath = typeof(TestConfig).Assembly.Location; + var configMap = new ExeConfigurationFileMap { ExeConfigFilename = assemblyPath + ".config" }; + var config = ConfigurationManager.OpenMappedExeConfiguration(configMap, ConfigurationUserLevel.None); + + var result = new NameValueCollection(); + foreach (KeyValueConfigurationElement setting in config.AppSettings.Settings) + { + result[setting.Key] = setting.Value; + } + return result; + } + } +} diff --git a/smsapiTests/VmsTest.cs b/smsapiTests/VmsTest.cs index 2360922..24978f2 100644 --- a/smsapiTests/VmsTest.cs +++ b/smsapiTests/VmsTest.cs @@ -28,9 +28,7 @@ public void DeletingSentMessage_EmptyResponse() ids[i] = sendResponse.List[i].ID; } - Countable deletedResponse = _factory.ActionDelete().Ids(ids).Execute(); - - Assert.AreEqual(0, deletedResponse.Count); + Assert.ThrowsException(() => _factory.ActionDelete().Ids(ids).Execute()); } [TestMethod] diff --git a/smsapiTests/smsapiTests.csproj b/smsapiTests/smsapiTests.csproj index d77a07e..020016c 100644 --- a/smsapiTests/smsapiTests.csproj +++ b/smsapiTests/smsapiTests.csproj @@ -1,17 +1,17 @@  - netcoreapp3.1;net5.0;net6.0;net7.0 + netcoreapp3.1;net5.0;net6.0;net7.0;net8.0 false - + - + @@ -20,6 +20,7 @@ - + + \ No newline at end of file From 240988c8631b617e23e9d3b4e4c872714436a72c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20=C5=81abno?= Date: Tue, 19 May 2026 13:04:17 +0200 Subject: [PATCH 2/4] Fix contract - contacts returns group's response null contacts counter --- smsapi/Api/Response/Group.cs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/smsapi/Api/Response/Group.cs b/smsapi/Api/Response/Group.cs index 42a2c64..f89b4d6 100644 --- a/smsapi/Api/Response/Group.cs +++ b/smsapi/Api/Response/Group.cs @@ -25,9 +25,15 @@ public class Group : Base private Group() { } - [DataMember(Name = "contacts_count", IsRequired = false)] public int ContactsCount { get; private set; } + [DataMember(Name = "contacts_count", IsRequired = false)] + private int? ContactsCountSerializationHelper + { + get => ContactsCount; + set => ContactsCount = value ?? 0; + } + public DateTime? DateCreated { get; private set; } public DateTime? DateUpdated { get; private set; } @@ -44,13 +50,19 @@ public string Info } [Obsolete("use ContactsCount instead")] - [DataMember(Name = "numbers_count", IsRequired = false)] public uint NumbersCount { get => (uint)ContactsCount; private set => ContactsCount = (int)value; } + [DataMember(Name = "numbers_count", IsRequired = false)] + private int? NumbersCountSerializationHelper + { + get => ContactsCount; + set => ContactsCount = value ?? ContactsCount; + } + public List Permissions { get From fc903d2fac4b2e7837c834b756539e32a67481b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20=C5=81abno?= Date: Tue, 19 May 2026 13:05:56 +0200 Subject: [PATCH 3/4] Add support for .net 8 --- smsapi/smsapi.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/smsapi/smsapi.csproj b/smsapi/smsapi.csproj index 6a6954a..b32cc5e 100644 --- a/smsapi/smsapi.csproj +++ b/smsapi/smsapi.csproj @@ -3,7 +3,7 @@ 8.0.30703 2.0 - netcoreapp3.1;net5.0;net6.0;net7.0 + netcoreapp3.1;net5.0;net6.0;net7.0;net8.0 false false 9.0 @@ -26,7 +26,7 @@ SMSAPI Client that allows to send SMS, MMS, VMS and manage your SMSAPI account. SMSAPI Client that allows to send SMS, MMS, VMS and manage your SMSAPI account. smsapi;sms;marketing;shipment;mms;vms;message - net6.0;net7.0;netcoreapp3.1 + netcoreapp3.1;net6.0;net7.0;net8.0 True From fd09773d1f618c463dd6f997c18aee615ad57aed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20=C5=81abno?= Date: Tue, 19 May 2026 13:13:09 +0200 Subject: [PATCH 4/4] Fix using sms templates --- smsapi/Api/Action/SMS/Send.cs | 2 +- smsapiTests/SmsSendValidateTest.cs | 53 ++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 smsapiTests/SmsSendValidateTest.cs diff --git a/smsapi/Api/Action/SMS/Send.cs b/smsapi/Api/Action/SMS/Send.cs index 7f2e8b5..63daa13 100644 --- a/smsapi/Api/Action/SMS/Send.cs +++ b/smsapi/Api/Action/SMS/Send.cs @@ -191,7 +191,7 @@ protected override void Validate() throw new ArgumentException("Cannot use 'to' and 'group' at the same time!"); } - if (text == null) + if (text == null && template == null) { throw new ArgumentException("Cannot send message without text!"); } diff --git a/smsapiTests/SmsSendValidateTest.cs b/smsapiTests/SmsSendValidateTest.cs new file mode 100644 index 0000000..6d4b79f --- /dev/null +++ b/smsapiTests/SmsSendValidateTest.cs @@ -0,0 +1,53 @@ +using System; +using System.Reflection; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using SMSApi.Api.Action; + +namespace smsapiTests +{ + [TestClass] + public class SmsSendValidateTest + { + [TestMethod] + public void Validate_TextAndTemplateBothNull_Throws() + { + var send = new SMSSend().SetTo("48000000000"); + + var ex = Assert.ThrowsException(() => InvokeValidate(send)); + Assert.IsInstanceOfType(ex.InnerException, typeof(ArgumentException)); + Assert.AreEqual("Cannot send message without text!", ex.InnerException.Message); + } + + [TestMethod] + public void Validate_TextSet_DoesNotThrow() + { + var send = new SMSSend().SetTo("48000000000").SetText("hello"); + + InvokeValidate(send); + } + + [TestMethod] + public void Validate_TemplateSet_DoesNotThrow() + { + var send = new SMSSend().SetTo("48000000000").SetTemplate("welcome"); + + InvokeValidate(send); + } + + [TestMethod] + public void Validate_ToAndGroupBothSet_Throws() + { + var send = new SMSSend().SetTo("48000000000").SetGroup("g").SetText("hi"); + + var ex = Assert.ThrowsException(() => InvokeValidate(send)); + Assert.IsInstanceOfType(ex.InnerException, typeof(ArgumentException)); + Assert.AreEqual("Cannot use 'to' and 'group' at the same time!", ex.InnerException.Message); + } + + private static void InvokeValidate(SMSSend send) + { + var method = typeof(SMSSend).GetMethod("Validate", BindingFlags.Instance | BindingFlags.NonPublic); + method.Invoke(send, Array.Empty()); + } + } +}