From c7972fb9f5a413b2222ed173a27ef7fa98be2b12 Mon Sep 17 00:00:00 2001 From: Sukhorukov Anton Date: Mon, 12 Feb 2024 13:57:45 +0300 Subject: [PATCH 01/11] fix MessagesRepository --- .../Data/MessagesRepository.cs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/common/ASC.MessagingSystem/Data/MessagesRepository.cs b/common/ASC.MessagingSystem/Data/MessagesRepository.cs index c7ff0cbc2ad..0054172e462 100644 --- a/common/ASC.MessagingSystem/Data/MessagesRepository.cs +++ b/common/ASC.MessagingSystem/Data/MessagesRepository.cs @@ -109,7 +109,7 @@ public async Task AddAsync(EventMessage message) } var now = DateTime.UtcNow; - var key = string.Format("{0}|{1}|{2}|{3}", message.TenantId, message.UserId, message.Id, now.Ticks); + var key = $"{message.TenantId}|{message.UserId}|{message.Id}|{now.Ticks}"; await _semaphore.WaitAsync(); @@ -140,8 +140,9 @@ private async Task FlushCacheAsync() if (DateTime.UtcNow > _lastSave.Add(_cacheTime) || _cache.Count > _cacheLimit) { - lock (_cache) + try { + await _semaphore.WaitAsync(); _timer.Change(-1, -1); _timerStarted = false; @@ -149,6 +150,10 @@ private async Task FlushCacheAsync() _cache.Clear(); _lastSave = DateTime.UtcNow; } + finally + { + _semaphore.Release(); + } } if (events == null) @@ -209,8 +214,9 @@ private void FlushCache() { List events; - lock (_cache) + try { + _semaphore.Wait(); _timer.Change(-1, -1); _timerStarted = false; @@ -218,6 +224,10 @@ private void FlushCache() _cache.Clear(); _lastSave = DateTime.UtcNow; } + finally + { + _semaphore.Release(); + } using var scope = _serviceScopeFactory.CreateScope(); using var ef = scope.ServiceProvider.GetService>().CreateDbContext(); From 0672c2623821ac15a02d10cb0511dc3635c84ada Mon Sep 17 00:00:00 2001 From: Sukhorukov Anton Date: Mon, 12 Feb 2024 16:52:23 +0300 Subject: [PATCH 02/11] add logs --- common/ASC.MessagingSystem/Data/MessagesRepository.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/common/ASC.MessagingSystem/Data/MessagesRepository.cs b/common/ASC.MessagingSystem/Data/MessagesRepository.cs index 0054172e462..7d70cc52b51 100644 --- a/common/ASC.MessagingSystem/Data/MessagesRepository.cs +++ b/common/ASC.MessagingSystem/Data/MessagesRepository.cs @@ -81,6 +81,8 @@ public async Task AddAsync(EventMessage message) { if (ForseSave(message)) { + _logger.LogDebug("ForseSave: {action}", message.Action.ToStringFast()); + int id; if (!string.IsNullOrEmpty(message.UAHeader)) { @@ -110,11 +112,12 @@ public async Task AddAsync(EventMessage message) var now = DateTime.UtcNow; var key = $"{message.TenantId}|{message.UserId}|{message.Id}|{now.Ticks}"; - - await _semaphore.WaitAsync(); + + _logger.LogDebug("AddToCache: {key}, semaphore current {CurrentCount}", key, _semaphore.CurrentCount); try { + await _semaphore.WaitAsync(); _cache[key] = message; if (!_timerStarted) @@ -160,6 +163,8 @@ private async Task FlushCacheAsync() { return; } + + _logger.LogDebug("FlushCache: events count {Count}", events.Count); using var scope = _serviceScopeFactory.CreateScope(); await using var ef = await scope.ServiceProvider.GetService>().CreateDbContextAsync(); From 84544a43aa62dfde0c6aafe15be57ca8426fd879 Mon Sep 17 00:00:00 2001 From: Andrey Savihin Date: Thu, 8 Feb 2024 14:48:24 +0300 Subject: [PATCH 03/11] ASC.Core.Common: TenantDomainValidator: added regular expression to check tenant name # Conflicts: # web/ASC.Web.Api/Api/Settings/GreetingSettingsController.cs --- .../Caching/CachedTenantService.cs | 5 +++++ .../Context/Impl/TenantManager.cs | 5 +++++ common/ASC.Core.Common/Core/ITenantService.cs | 1 + common/ASC.Core.Common/Data/DbTenantService.cs | 7 ++++++- common/ASC.Core.Common/HostedSolution.cs | 2 ++ .../Tenants/TenantDomainValidator.cs | 17 ++++++++++++++++- .../Api/Settings/GreetingSettingsController.cs | 13 +++++++++++++ 7 files changed, 48 insertions(+), 2 deletions(-) diff --git a/common/ASC.Core.Common/Caching/CachedTenantService.cs b/common/ASC.Core.Common/Caching/CachedTenantService.cs index 88441b97c9f..4338165efe0 100644 --- a/common/ASC.Core.Common/Caching/CachedTenantService.cs +++ b/common/ASC.Core.Common/Caching/CachedTenantService.cs @@ -190,6 +190,11 @@ public async Task ValidateDomainAsync(string domain) await _service.ValidateDomainAsync(domain); } + public void ValidateTenantName(string name) + { + _service.ValidateTenantName(name); + } + public async Task> GetTenantsAsync(string login, string passwordHash) { return await _service.GetTenantsAsync(login, passwordHash); diff --git a/common/ASC.Core.Common/Context/Impl/TenantManager.cs b/common/ASC.Core.Common/Context/Impl/TenantManager.cs index 0157238088a..4f17cf8c1d4 100644 --- a/common/ASC.Core.Common/Context/Impl/TenantManager.cs +++ b/common/ASC.Core.Common/Context/Impl/TenantManager.cs @@ -445,4 +445,9 @@ public async Task> FindTenantQuotaRowsAsync(int tenantId) { return (await QuotaService.FindTenantQuotaRowsAsync(tenantId)).ToList(); } + + public void ValidateTenantName(string name) + { + TenantService.ValidateTenantName(name); + } } diff --git a/common/ASC.Core.Common/Core/ITenantService.cs b/common/ASC.Core.Common/Core/ITenantService.cs index f2cb734ed04..4b4ccf69ab1 100644 --- a/common/ASC.Core.Common/Core/ITenantService.cs +++ b/common/ASC.Core.Common/Core/ITenantService.cs @@ -48,4 +48,5 @@ public interface ITenantService Task PermanentlyRemoveTenantAsync(int id); void SetTenantSettings(int tenant, string key, byte[] data); Task ValidateDomainAsync(string domain); + void ValidateTenantName(string name); } diff --git a/common/ASC.Core.Common/Data/DbTenantService.cs b/common/ASC.Core.Common/Data/DbTenantService.cs index 8cbc114bf43..86142614c9e 100644 --- a/common/ASC.Core.Common/Data/DbTenantService.cs +++ b/common/ASC.Core.Common/Data/DbTenantService.cs @@ -59,7 +59,12 @@ public async Task ValidateDomainAsync(string domain) // using var tr = TenantDbContext.Database.BeginTransaction(); await ValidateDomainAsync(domain, Tenant.DefaultTenant, true); } - + + public void ValidateTenantName(string name) + { + tenantDomainValidator.ValidateTenantName(name); + } + public IEnumerable GetTenantsWithCsp() { var cspSettingsId = new CspSettings().ID; diff --git a/common/ASC.Core.Common/HostedSolution.cs b/common/ASC.Core.Common/HostedSolution.cs index 519fe1bba6e..4dfac048dfd 100644 --- a/common/ASC.Core.Common/HostedSolution.cs +++ b/common/ASC.Core.Common/HostedSolution.cs @@ -128,6 +128,8 @@ public async Task RegisterTenantAsync(TenantRegistrationInfo registratio registrationInfo.PasswordHash = Guid.NewGuid().ToString(); } + tenantService.ValidateTenantName(registrationInfo.Name); + // create tenant var tenant = new Tenant(registrationInfo.Address.ToLowerInvariant()) { diff --git a/common/ASC.Core.Common/Tenants/TenantDomainValidator.cs b/common/ASC.Core.Common/Tenants/TenantDomainValidator.cs index a06cb6acbba..5bbadca7011 100644 --- a/common/ASC.Core.Common/Tenants/TenantDomainValidator.cs +++ b/common/ASC.Core.Common/Tenants/TenantDomainValidator.cs @@ -30,12 +30,13 @@ namespace ASC.Core.Tenants; public class TenantDomainValidator { private readonly Regex _validDomain; + private readonly Regex _validName; public string Regex { get; } public int MinLength { get; } public int MaxLength { get; } - public TenantDomainValidator(IConfiguration configuration) + public TenantDomainValidator(IConfiguration configuration, CoreBaseSettings coreBaseSettings) { MaxLength = 100; @@ -60,6 +61,12 @@ public TenantDomainValidator(IConfiguration configuration) } _validDomain = new Regex(Regex, RegexOptions.Compiled | RegexOptions.CultureInvariant | RegexOptions.IgnoreCase); + + var nameRegexpFromConfig = configuration["core:tenantname:regex"]; + if (!coreBaseSettings.Standalone && !string.IsNullOrEmpty(nameRegexpFromConfig)) + { + _validName = new Regex(nameRegexpFromConfig, RegexOptions.Compiled | RegexOptions.CultureInvariant | RegexOptions.IgnoreCase); + } } public void ValidateDomainLength(string domain) @@ -78,4 +85,12 @@ public void ValidateDomainCharacters(string domain) throw new TenantIncorrectCharsException("Domain contains invalid characters."); } } + + public void ValidateTenantName(string name) + { + if (!string.IsNullOrEmpty(name) && _validName != null && !_validName.IsMatch(name)) + { + throw new TenantIncorrectCharsException("Name contains invalid characters."); + } + } } diff --git a/web/ASC.Web.Api/Api/Settings/GreetingSettingsController.cs b/web/ASC.Web.Api/Api/Settings/GreetingSettingsController.cs index 5cf8a868736..127491ed012 100644 --- a/web/ASC.Web.Api/Api/Settings/GreetingSettingsController.cs +++ b/web/ASC.Web.Api/Api/Settings/GreetingSettingsController.cs @@ -32,6 +32,7 @@ public class GreetingSettingsController : BaseSettingsController private readonly TenantManager _tenantManager; private readonly PermissionContext _permissionContext; private readonly TenantInfoSettingsHelper _tenantInfoSettingsHelper; + private readonly CoreBaseSettings _coreBaseSettings; public GreetingSettingsController( TenantInfoSettingsHelper tenantInfoSettingsHelper, @@ -41,12 +42,14 @@ public GreetingSettingsController( PermissionContext permissionContext, WebItemManager webItemManager, IMemoryCache memoryCache, + CoreBaseSettings coreBaseSettings, IHttpContextAccessor httpContextAccessor) : base(apiContext, memoryCache, webItemManager, httpContextAccessor) { _tenantInfoSettingsHelper = tenantInfoSettingsHelper; _messageService = messageService; _tenantManager = tenantManager; _permissionContext = permissionContext; + _coreBaseSettings = coreBaseSettings; } /// @@ -94,6 +97,16 @@ public async Task SaveGreetingSettingsAsync(GreetingSettingsRequestsDto await _permissionContext.DemandPermissionsAsync(SecurityConstants.EditPortalSettings); var tenant = await _tenantManager.GetCurrentTenantAsync(); + + if (!_coreBaseSettings.Standalone) + { + var quota = await _tenantManager.GetTenantQuotaAsync(tenant.Id); + if (quota.Free || quota.Trial) + { + _tenantManager.ValidateTenantName(inDto.Title); + } + } + tenant.Name = inDto.Title; await _tenantManager.SaveTenantAsync(tenant); From 2ad56f44c3ad593132ccecf150bc8a6f221f5688 Mon Sep 17 00:00:00 2001 From: Andrey Savihin Date: Tue, 6 Feb 2024 12:28:42 +0300 Subject: [PATCH 04/11] ASC.MessagingSystem: MessageSettings: added check for null before getting IP (Error while parse Http Request for FileConverted type of event) --- common/ASC.MessagingSystem/Core/MessageSettings.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/ASC.MessagingSystem/Core/MessageSettings.cs b/common/ASC.MessagingSystem/Core/MessageSettings.cs index 9f52a31e195..4d3b566b31d 100644 --- a/common/ASC.MessagingSystem/Core/MessageSettings.cs +++ b/common/ASC.MessagingSystem/Core/MessageSettings.cs @@ -67,7 +67,7 @@ public static string GetReferer(IDictionary headers) public static string GetIP(HttpRequest request) { - return request.HttpContext.Connection.RemoteIpAddress?.ToString(); + return request?.HttpContext?.Connection.RemoteIpAddress?.ToString(); } public static void AddInfoMessage(EventMessage message, Dictionary dict = null) From 5339a3b48ac95b5fd26160898153eab896f1f9c1 Mon Sep 17 00:00:00 2001 From: Andrey Savihin Date: Mon, 5 Feb 2024 18:13:31 +0300 Subject: [PATCH 05/11] ASC.Core.Common: GeolocationHelper: added check for null before parsing IP --- common/ASC.Core.Common/GeolocationHelper.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/common/ASC.Core.Common/GeolocationHelper.cs b/common/ASC.Core.Common/GeolocationHelper.cs index 7b5f4647cf3..cc03f3de90b 100644 --- a/common/ASC.Core.Common/GeolocationHelper.cs +++ b/common/ASC.Core.Common/GeolocationHelper.cs @@ -67,6 +67,10 @@ public async Task GetGeolocationAsync(string ip) { try { + if (string.IsNullOrEmpty(ip)) + { + return new[] { string.Empty, string.Empty }; + } var location = await GetIPGeolocationAsync(IPAddress.Parse(ip)); if (string.IsNullOrEmpty(location.Key) || (location.Key == "ZZ")) { From 63c79daf654df97cd0bda9e782774d78992838f8 Mon Sep 17 00:00:00 2001 From: Andrey Savihin Date: Tue, 6 Feb 2024 21:51:37 +0300 Subject: [PATCH 06/11] ASC.Core.Common: GeolocationHelper: fix for parsing IP --- common/ASC.Core.Common/GeolocationHelper.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/ASC.Core.Common/GeolocationHelper.cs b/common/ASC.Core.Common/GeolocationHelper.cs index cc03f3de90b..2c2bbfe2892 100644 --- a/common/ASC.Core.Common/GeolocationHelper.cs +++ b/common/ASC.Core.Common/GeolocationHelper.cs @@ -67,11 +67,11 @@ public async Task GetGeolocationAsync(string ip) { try { - if (string.IsNullOrEmpty(ip)) + if (!IPAddress.TryParse(ip, out var address)) { return new[] { string.Empty, string.Empty }; } - var location = await GetIPGeolocationAsync(IPAddress.Parse(ip)); + var location = await GetIPGeolocationAsync(address); if (string.IsNullOrEmpty(location.Key) || (location.Key == "ZZ")) { return new[] { string.Empty, string.Empty }; From baa4511aef93665fd28c5cf83e4349e1903e7897 Mon Sep 17 00:00:00 2001 From: Andrey Savihin Date: Mon, 5 Feb 2024 18:07:38 +0300 Subject: [PATCH 07/11] ASC.Web.Core: :StudioPeriodicNotify: fix error in notify logs (DateTime.MaxValue.ToString throw exception in ar-SA Culture) --- web/ASC.Web.Core/Notify/StudioPeriodicNotify.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/web/ASC.Web.Core/Notify/StudioPeriodicNotify.cs b/web/ASC.Web.Core/Notify/StudioPeriodicNotify.cs index 289418e03f2..8d758663291 100644 --- a/web/ASC.Web.Core/Notify/StudioPeriodicNotify.cs +++ b/web/ASC.Web.Core/Notify/StudioPeriodicNotify.cs @@ -379,8 +379,8 @@ await client.SendNoticeToAsync( new TagValue(Tags.ActiveUsers, (await _userManager.GetUsersAsync()).Length), new TagValue(Tags.Price, rquota.Price), new TagValue(Tags.PricePeriod, UserControlsCommonResource.TariffPerMonth), - new TagValue(Tags.DueDate, dueDate.ToLongDateString()), - new TagValue(Tags.DelayDueDate, (delayDueDateIsNotMax ? delayDueDate : dueDate).ToLongDateString()), + //new TagValue(Tags.DueDate, dueDate.ToLongDateString()), + //new TagValue(Tags.DelayDueDate, (delayDueDateIsNotMax ? delayDueDate : dueDate).ToLongDateString()), TagValues.OrangeButton(orangeButtonText(culture), orangeButtonUrl), TagValues.TrulyYours(_studioNotifyHelper, txtTrulyYours(culture)), new TagValue("IMG1", img1), @@ -525,8 +525,8 @@ await client.SendNoticeToAsync( new TagValue(Tags.ActiveUsers, (await _userManager.GetUsersAsync()).Length), new TagValue(Tags.Price, rquota.Price), new TagValue(Tags.PricePeriod, UserControlsCommonResource.TariffPerMonth), - new TagValue(Tags.DueDate, dueDate.ToLongDateString()), - new TagValue(Tags.DelayDueDate, (delayDueDateIsNotMax ? delayDueDate : dueDate).ToLongDateString()), + //new TagValue(Tags.DueDate, dueDate.ToLongDateString()), + //new TagValue(Tags.DelayDueDate, (delayDueDateIsNotMax ? delayDueDate : dueDate).ToLongDateString()), TagValues.OrangeButton(orangeButtonText(culture), orangeButtonUrl), TagValues.TrulyYours(_studioNotifyHelper, txtTrulyYours(culture)), new TagValue("IMG1", img1), From 079a9338d12c34a81a670eec150af06f196670bd Mon Sep 17 00:00:00 2001 From: Andrey Savihin Date: Mon, 5 Feb 2024 17:37:52 +0300 Subject: [PATCH 08/11] ASC.Web.Core: StudioWhatsNewNotify: fix error in notify logs (FileUpdatedRevisionComment audit event is written to the database without room information) --- .../Core/Configuration/ProductEntryPoint.cs | 15 ++++++++++++--- .../ASC.Files/Core/Core/FileStorageService.cs | 2 +- web/ASC.Web.Core/IProduct.cs | 2 +- web/ASC.Web.Core/Notify/StudioWhatsNewNotify.cs | 2 +- web/ASC.Web.Core/Product.cs | 2 +- 5 files changed, 16 insertions(+), 7 deletions(-) diff --git a/products/ASC.Files/Core/Configuration/ProductEntryPoint.cs b/products/ASC.Files/Core/Configuration/ProductEntryPoint.cs index b6c8a41ae72..777300a2b7d 100644 --- a/products/ASC.Files/Core/Configuration/ProductEntryPoint.cs +++ b/products/ASC.Files/Core/Configuration/ProductEntryPoint.cs @@ -140,7 +140,7 @@ public string GetModuleResource(string ResourceClassTypeName, string ResourseKey } } - public override async Task> GetAuditEventsAsync(DateTime scheduleDate, Guid userId, Tenant tenant, WhatsNewType whatsNewType) + public override async Task> GetAuditEventsAsync(DateTime scheduleDate, Guid userId, Tenant tenant, WhatsNewType whatsNewType, ILogger logger) { IEnumerable events; _tenantManager.SetCurrentTenant(tenant); @@ -203,8 +203,17 @@ public override async Task> GetAuditEventsAsync(DateTi activityInfo.FileUrl = _commonLinkUtility.GetFullAbsolutePath(_filesLinkUtility.GetFileWebEditorUrl(e.Target.GetItems().FirstOrDefault())); } - var obj = e.Description.LastOrDefault(); - var additionalInfo = JsonSerializer.Deserialize(obj); + AdditionalNotificationInfo additionalInfo; + + try + { + additionalInfo = JsonSerializer.Deserialize(e.Description.LastOrDefault()); + } + catch (Exception ex) + { + logger.ErrorWithException("Error deserializing audit event: " + e.Id, ex); + continue; + } activityInfo.TargetUsers = additionalInfo.UserIds; diff --git a/products/ASC.Files/Core/Core/FileStorageService.cs b/products/ASC.Files/Core/Core/FileStorageService.cs index 1331fbdaf2e..00435a48fb7 100644 --- a/products/ASC.Files/Core/Core/FileStorageService.cs +++ b/products/ASC.Files/Core/Core/FileStorageService.cs @@ -1221,7 +1221,7 @@ public async Task UpdateCommentAsync(T fileId, int version, string co comment = await fileDao.UpdateCommentAsync(fileId, version, comment); - await _filesMessageService.SendAsync(MessageAction.FileUpdatedRevisionComment, file, file.Title, version.ToString(CultureInfo.InvariantCulture)); + await _filesMessageService.SendAsync(MessageAction.FileUpdatedRevisionComment, file, new[] { file.Title, version.ToString(CultureInfo.InvariantCulture) }); return comment; } diff --git a/web/ASC.Web.Core/IProduct.cs b/web/ASC.Web.Core/IProduct.cs index a8e06ca8f2b..bc344905180 100644 --- a/web/ASC.Web.Core/IProduct.cs +++ b/web/ASC.Web.Core/IProduct.cs @@ -38,5 +38,5 @@ public interface IProduct : IWebItem void Shutdown(); - Task> GetAuditEventsAsync(DateTime scheduleDate, Guid userId, Tenant tenant,WhatsNewType whatsNewType); + Task> GetAuditEventsAsync(DateTime scheduleDate, Guid userId, Tenant tenant,WhatsNewType whatsNewType, ILogger logger); } diff --git a/web/ASC.Web.Core/Notify/StudioWhatsNewNotify.cs b/web/ASC.Web.Core/Notify/StudioWhatsNewNotify.cs index 4bbcf350069..1e35db68343 100644 --- a/web/ASC.Web.Core/Notify/StudioWhatsNewNotify.cs +++ b/web/ASC.Web.Core/Notify/StudioWhatsNewNotify.cs @@ -176,7 +176,7 @@ private async Task SendMsgWhatsNewAsync(int tenantid, DateTime scheduleDate, Wha foreach (var p in products) { - auditEvents.AddRange(await p.GetAuditEventsAsync(scheduleDate, user.Id, tenant, whatsNewType)); + auditEvents.AddRange(await p.GetAuditEventsAsync(scheduleDate, user.Id, tenant, whatsNewType, _log)); } _log.Debug($"SendMsgWhatsNew auditEvents count : {auditEvents.Count}");//temp diff --git a/web/ASC.Web.Core/Product.cs b/web/ASC.Web.Core/Product.cs index 35729477fb6..f1f14d147f5 100644 --- a/web/ASC.Web.Core/Product.cs +++ b/web/ASC.Web.Core/Product.cs @@ -49,7 +49,7 @@ public abstract class Product : IProduct public virtual void Shutdown() { } - public virtual Task> GetAuditEventsAsync(DateTime scheduleDate, Guid userId, Tenant tenant, WhatsNewType whatsNewType) + public virtual Task> GetAuditEventsAsync(DateTime scheduleDate, Guid userId, Tenant tenant, WhatsNewType whatsNewType, ILogger logger) { return Task.FromResult(Enumerable.Empty()); } From dce6f8adbf5a03af08be97c47c8911c7fd63e175 Mon Sep 17 00:00:00 2001 From: Andrey Savihin Date: Wed, 7 Feb 2024 10:28:48 +0300 Subject: [PATCH 09/11] ASC.Web.Core: StudioWhatsNewNotify: refactoring 48b941f368c768811c4859b20d25441618dc3acc # Conflicts: # products/ASC.Files/Core/Configuration/ProductEntryPoint.cs # products/ASC.Files/Server/ProductEntryPoint.cs # web/ASC.Web.Core/IProduct.cs # web/ASC.Web.Core/Notify/StudioWhatsNewNotify.cs # web/ASC.Web.Core/Product.cs --- .../Core/Configuration/ProductEntryPoint.cs | 9 ++++-- .../Core/Log/ProductEntryPointLogger.cs | 32 +++++++++++++++++++ .../ASC.Files/Server/ProductEntryPoint.cs | 6 ++-- web/ASC.Web.Core/IProduct.cs | 2 +- .../Notify/StudioWhatsNewNotify.cs | 2 +- web/ASC.Web.Core/Product.cs | 2 +- 6 files changed, 45 insertions(+), 8 deletions(-) create mode 100644 products/ASC.Files/Core/Log/ProductEntryPointLogger.cs diff --git a/products/ASC.Files/Core/Configuration/ProductEntryPoint.cs b/products/ASC.Files/Core/Configuration/ProductEntryPoint.cs index 777300a2b7d..f10093a971d 100644 --- a/products/ASC.Files/Core/Configuration/ProductEntryPoint.cs +++ b/products/ASC.Files/Core/Configuration/ProductEntryPoint.cs @@ -45,6 +45,7 @@ public class ProductEntryPoint : Product private readonly CommonLinkUtility _commonLinkUtility; private readonly FileSecurity _fileSecurity; private readonly GlobalFolder _globalFolder; + private readonly ILogger _logger; //public SubscriptionManager SubscriptionManager { get; } @@ -64,7 +65,8 @@ public ProductEntryPoint( FilesLinkUtility filesLinkUtility, FileSecurity fileSecurity, GlobalFolder globalFolder, - CommonLinkUtility commonLinkUtility + CommonLinkUtility commonLinkUtility, + ILogger logger // SubscriptionManager subscriptionManager ) { @@ -82,6 +84,7 @@ CommonLinkUtility commonLinkUtility _fileSecurity = fileSecurity; _globalFolder = globalFolder; _commonLinkUtility = commonLinkUtility; + _logger = logger; //SubscriptionManager = subscriptionManager; } @@ -140,7 +143,7 @@ public string GetModuleResource(string ResourceClassTypeName, string ResourseKey } } - public override async Task> GetAuditEventsAsync(DateTime scheduleDate, Guid userId, Tenant tenant, WhatsNewType whatsNewType, ILogger logger) + public override async Task> GetAuditEventsAsync(DateTime scheduleDate, Guid userId, Tenant tenant, WhatsNewType whatsNewType) { IEnumerable events; _tenantManager.SetCurrentTenant(tenant); @@ -211,7 +214,7 @@ public override async Task> GetAuditEventsAsync(DateTi } catch (Exception ex) { - logger.ErrorWithException("Error deserializing audit event: " + e.Id, ex); + _logger.ErrorDeserializingAuditEvent(e.Id, ex); continue; } diff --git a/products/ASC.Files/Core/Log/ProductEntryPointLogger.cs b/products/ASC.Files/Core/Log/ProductEntryPointLogger.cs new file mode 100644 index 00000000000..9cf2776bb27 --- /dev/null +++ b/products/ASC.Files/Core/Log/ProductEntryPointLogger.cs @@ -0,0 +1,32 @@ +// (c) Copyright Ascensio System SIA 2010-2023 +// +// This program is a free software product. +// You can redistribute it and/or modify it under the terms +// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software +// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended +// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of +// any third-party rights. +// +// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty +// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see +// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html +// +// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021. +// +// The interactive user interfaces in modified source and object code versions of the Program must +// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3. +// +// Pursuant to Section 7(b) of the License you must retain the original Product logo when +// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under +// trademark law for use of our trademarks. +// +// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing +// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0 +// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode + +namespace ASC.Files.Core.Log; +internal static partial class ProductEntryPointLogger +{ + [LoggerMessage(Level = LogLevel.Error, Message = "Error while deserializing audit event: {eventId}")] + public static partial void ErrorDeserializingAuditEvent(this ILogger logger, int eventId, Exception exception); +} diff --git a/products/ASC.Files/Server/ProductEntryPoint.cs b/products/ASC.Files/Server/ProductEntryPoint.cs index 5ac33d73294..d339e20e818 100644 --- a/products/ASC.Files/Server/ProductEntryPoint.cs +++ b/products/ASC.Files/Server/ProductEntryPoint.cs @@ -51,7 +51,8 @@ public ApiProductEntryPoint( FilesLinkUtility filesLinkUtility, FileSecurity fileSecurity, GlobalFolder globalFolder, - CommonLinkUtility commonLinkUtility + CommonLinkUtility commonLinkUtility, + ILogger logger //SubscriptionManager subscriptionManager ) : base(filesSpaceUsageStatManager, coreBaseSettings, @@ -66,7 +67,8 @@ CommonLinkUtility commonLinkUtility filesLinkUtility, fileSecurity, globalFolder, - commonLinkUtility) + commonLinkUtility, + logger) { } diff --git a/web/ASC.Web.Core/IProduct.cs b/web/ASC.Web.Core/IProduct.cs index bc344905180..a8e06ca8f2b 100644 --- a/web/ASC.Web.Core/IProduct.cs +++ b/web/ASC.Web.Core/IProduct.cs @@ -38,5 +38,5 @@ public interface IProduct : IWebItem void Shutdown(); - Task> GetAuditEventsAsync(DateTime scheduleDate, Guid userId, Tenant tenant,WhatsNewType whatsNewType, ILogger logger); + Task> GetAuditEventsAsync(DateTime scheduleDate, Guid userId, Tenant tenant,WhatsNewType whatsNewType); } diff --git a/web/ASC.Web.Core/Notify/StudioWhatsNewNotify.cs b/web/ASC.Web.Core/Notify/StudioWhatsNewNotify.cs index 1e35db68343..4bbcf350069 100644 --- a/web/ASC.Web.Core/Notify/StudioWhatsNewNotify.cs +++ b/web/ASC.Web.Core/Notify/StudioWhatsNewNotify.cs @@ -176,7 +176,7 @@ private async Task SendMsgWhatsNewAsync(int tenantid, DateTime scheduleDate, Wha foreach (var p in products) { - auditEvents.AddRange(await p.GetAuditEventsAsync(scheduleDate, user.Id, tenant, whatsNewType, _log)); + auditEvents.AddRange(await p.GetAuditEventsAsync(scheduleDate, user.Id, tenant, whatsNewType)); } _log.Debug($"SendMsgWhatsNew auditEvents count : {auditEvents.Count}");//temp diff --git a/web/ASC.Web.Core/Product.cs b/web/ASC.Web.Core/Product.cs index f1f14d147f5..35729477fb6 100644 --- a/web/ASC.Web.Core/Product.cs +++ b/web/ASC.Web.Core/Product.cs @@ -49,7 +49,7 @@ public abstract class Product : IProduct public virtual void Shutdown() { } - public virtual Task> GetAuditEventsAsync(DateTime scheduleDate, Guid userId, Tenant tenant, WhatsNewType whatsNewType, ILogger logger) + public virtual Task> GetAuditEventsAsync(DateTime scheduleDate, Guid userId, Tenant tenant, WhatsNewType whatsNewType) { return Task.FromResult(Enumerable.Empty()); } From 878c5a4df97227d74d56f859cd1007ca3fb8f58f Mon Sep 17 00:00:00 2001 From: Andrey Savihin Date: Fri, 16 Feb 2024 16:50:59 +0300 Subject: [PATCH 10/11] fix cherry-pick 84544a43aa62dfde0c6aafe15be57ca8426fd879 --- common/ASC.Core.Common/Data/DbTenantService.cs | 2 +- common/ASC.Core.Common/HostedSolution.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/common/ASC.Core.Common/Data/DbTenantService.cs b/common/ASC.Core.Common/Data/DbTenantService.cs index 86142614c9e..f53a6d629a6 100644 --- a/common/ASC.Core.Common/Data/DbTenantService.cs +++ b/common/ASC.Core.Common/Data/DbTenantService.cs @@ -62,7 +62,7 @@ public async Task ValidateDomainAsync(string domain) public void ValidateTenantName(string name) { - tenantDomainValidator.ValidateTenantName(name); + _tenantDomainValidator.ValidateTenantName(name); } public IEnumerable GetTenantsWithCsp() diff --git a/common/ASC.Core.Common/HostedSolution.cs b/common/ASC.Core.Common/HostedSolution.cs index 4dfac048dfd..dd7c09f7cc0 100644 --- a/common/ASC.Core.Common/HostedSolution.cs +++ b/common/ASC.Core.Common/HostedSolution.cs @@ -128,7 +128,7 @@ public async Task RegisterTenantAsync(TenantRegistrationInfo registratio registrationInfo.PasswordHash = Guid.NewGuid().ToString(); } - tenantService.ValidateTenantName(registrationInfo.Name); + TenantService.ValidateTenantName(registrationInfo.Name); // create tenant var tenant = new Tenant(registrationInfo.Address.ToLowerInvariant()) From 28a208416031693d6b4a447122b1595ea0707375 Mon Sep 17 00:00:00 2001 From: Alexey Bannov Date: Mon, 19 Feb 2024 18:35:08 +0300 Subject: [PATCH 11/11] rate limit: fixed for sensitive_api --- common/ASC.Api.Core/Core/BaseStartup.cs | 5 +++-- products/ASC.People/Server/Api/UserController.cs | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/common/ASC.Api.Core/Core/BaseStartup.cs b/common/ASC.Api.Core/Core/BaseStartup.cs index d2820462fc2..f2bd97e9d5e 100644 --- a/common/ASC.Api.Core/Core/BaseStartup.cs +++ b/common/ASC.Api.Core/Core/BaseStartup.cs @@ -236,7 +236,8 @@ bool EnableNoLimiter(IPAddress address) { var userId = httpContext?.User?.Claims.FirstOrDefault(x => x.Type == ClaimTypes.Sid)?.Value; var permitLimit = 5; - var partitionKey = $"sensitive_api_{userId}"; + var path = httpContext.Request.Path.ToString(); + var partitionKey = $"sensitive_api_{userId}|{path}"; var remoteIpAddress = httpContext?.Connection.RemoteIpAddress; if (EnableNoLimiter(remoteIpAddress)) @@ -247,7 +248,7 @@ bool EnableNoLimiter(IPAddress address) return RedisRateLimitPartition.GetSlidingWindowRateLimiter(partitionKey, _ => new RedisSlidingWindowRateLimiterOptions { PermitLimit = permitLimit, - Window = TimeSpan.FromMinutes(1), + Window = TimeSpan.FromMinutes(15), ConnectionMultiplexerFactory = () => connectionMultiplexer }); }); diff --git a/products/ASC.People/Server/Api/UserController.cs b/products/ASC.People/Server/Api/UserController.cs index 19260712d9c..c904944941f 100644 --- a/products/ASC.People/Server/Api/UserController.cs +++ b/products/ASC.People/Server/Api/UserController.cs @@ -412,7 +412,6 @@ public async Task> InviteUsersAsync(InviteUsersRequestDto inDt /// api/2.0/people/{userid}/password /// PUT [HttpPut("{userid}/password")] - [EnableRateLimiting("sensitive_api")] [Authorize(AuthenticationSchemes = "confirm", Roles = "PasswordChange,EmailChange,Activation,EmailActivation,Everyone")] public async Task ChangeUserPassword(Guid userid, MemberRequestDto inDto) { @@ -1183,6 +1182,7 @@ public async Task SelfAsync() /// POST [AllowNotPayment] [HttpPost("email")] + [EnableRateLimiting("sensitive_api")] public async Task SendEmailChangeInstructionsAsync(UpdateMemberRequestDto inDto) { Guid.TryParse(inDto.UserId, out var userid);