Merge branch 'develop' into feature/tfa-sms

This commit is contained in:
Viktor Fomin 2023-09-13 11:42:07 +03:00
commit 8433b6931a
6 changed files with 1953 additions and 1918 deletions

View File

@ -24,6 +24,8 @@
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0 // 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 // International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
using Flurl.Util;
namespace ASC.Api.Core; namespace ASC.Api.Core;
public abstract class BaseStartup public abstract class BaseStartup
@ -109,7 +111,7 @@ public abstract class BaseStartup
if (userId == null) if (userId == null)
{ {
return RateLimitPartition.GetNoLimiter("no_limiter"); userId = httpContext?.Connection.RemoteIpAddress.ToInvariantString();
} }
var permitLimit = 1500; var permitLimit = 1500;
@ -133,7 +135,7 @@ public abstract class BaseStartup
if (userId == null) if (userId == null)
{ {
return RateLimitPartition.GetNoLimiter("no_limiter"); userId = httpContext?.Connection.RemoteIpAddress.ToInvariantString();
} }
if (String.Compare(httpContext.Request.Method, "GET", true) == 0) if (String.Compare(httpContext.Request.Method, "GET", true) == 0)
@ -154,17 +156,37 @@ public abstract class BaseStartup
QueueLimit = 0, QueueLimit = 0,
ConnectionMultiplexerFactory = () => connectionMultiplexer ConnectionMultiplexerFactory = () => connectionMultiplexer
}); });
} }),
)); PartitionedRateLimiter.Create<HttpContext, string>(httpContext =>
{
options.AddPolicy("sensitive_api", httpContext => {
var userId = httpContext?.User?.Claims.FirstOrDefault(x => x.Type == ClaimTypes.Sid)?.Value; var userId = httpContext?.User?.Claims.FirstOrDefault(x => x.Type == ClaimTypes.Sid)?.Value;
if (userId == null) if (userId == null)
{
userId = httpContext?.Connection.RemoteIpAddress.ToInvariantString();
}
var partitionKey = $"fw_post_put_{userId}";
var permitLimit = 10000;
if (!(String.Compare(httpContext.Request.Method, "POST", true) == 0 ||
String.Compare(httpContext.Request.Method, "PUT", true) == 0))
{ {
return RateLimitPartition.GetNoLimiter("no_limiter"); return RateLimitPartition.GetNoLimiter("no_limiter");
} }
return RedisRateLimitPartition.GetFixedWindowRateLimiter(partitionKey, key => new RedisFixedWindowRateLimiterOptions
{
PermitLimit = permitLimit,
Window = TimeSpan.FromDays(1),
ConnectionMultiplexerFactory = () => connectionMultiplexer
});
}
));
options.AddPolicy("sensitive_api", httpContext =>
{
var userId = httpContext?.User?.Claims.FirstOrDefault(x => x.Type == ClaimTypes.Sid)?.Value;
var permitLimit = 5; var permitLimit = 5;
var partitionKey = $"sensitive_api_{userId}"; var partitionKey = $"sensitive_api_{userId}";

View File

@ -3172,7 +3172,9 @@ public class FileStorageService //: IFileStorageService
} }
var link = await _invitationLinkService.GetInvitationLinkAsync(user.Email, share.Access, _authContext.CurrentAccount.ID); var link = await _invitationLinkService.GetInvitationLinkAsync(user.Email, share.Access, _authContext.CurrentAccount.ID);
await _studioNotifyService.SendEmailRoomInviteAsync(user.Email, room.Title, link); var shortenLink = await _urlShortener.GetShortenLinkAsync(link);
await _studioNotifyService.SendEmailRoomInviteAsync(user.Email, room.Title, shortenLink);
} }
} }

View File

@ -44,10 +44,9 @@ public class FileSharingAceHelper
private readonly FilesSettingsHelper _filesSettingsHelper; private readonly FilesSettingsHelper _filesSettingsHelper;
private readonly InvitationLinkService _invitationLinkService; private readonly InvitationLinkService _invitationLinkService;
private readonly StudioNotifyService _studioNotifyService; private readonly StudioNotifyService _studioNotifyService;
private readonly UsersInRoomChecker _usersInRoomChecker;
private readonly UserManagerWrapper _userManagerWrapper; private readonly UserManagerWrapper _userManagerWrapper;
private readonly CountPaidUserChecker _countPaidUserChecker; private readonly CountPaidUserChecker _countPaidUserChecker;
private readonly ILogger _logger; private readonly IUrlShortener _urlShortener;
public FileSharingAceHelper( public FileSharingAceHelper(
FileSecurity fileSecurity, FileSecurity fileSecurity,
@ -64,10 +63,9 @@ public class FileSharingAceHelper
FilesSettingsHelper filesSettingsHelper, FilesSettingsHelper filesSettingsHelper,
InvitationLinkService invitationLinkService, InvitationLinkService invitationLinkService,
StudioNotifyService studioNotifyService, StudioNotifyService studioNotifyService,
ILoggerProvider loggerProvider,
UsersInRoomChecker usersInRoomChecker,
UserManagerWrapper userManagerWrapper, UserManagerWrapper userManagerWrapper,
CountPaidUserChecker countPaidUserChecker) CountPaidUserChecker countPaidUserChecker,
IUrlShortener urlShortener)
{ {
_fileSecurity = fileSecurity; _fileSecurity = fileSecurity;
_coreBaseSettings = coreBaseSettings; _coreBaseSettings = coreBaseSettings;
@ -83,10 +81,9 @@ public class FileSharingAceHelper
_filesSettingsHelper = filesSettingsHelper; _filesSettingsHelper = filesSettingsHelper;
_invitationLinkService = invitationLinkService; _invitationLinkService = invitationLinkService;
_studioNotifyService = studioNotifyService; _studioNotifyService = studioNotifyService;
_usersInRoomChecker = usersInRoomChecker;
_logger = loggerProvider.CreateLogger("ASC.Files");
_userManagerWrapper = userManagerWrapper; _userManagerWrapper = userManagerWrapper;
_countPaidUserChecker = countPaidUserChecker; _countPaidUserChecker = countPaidUserChecker;
_urlShortener = urlShortener;
} }
public async Task<(bool, string)> SetAceObjectAsync<T>(List<AceWrapper> aceWrappers, FileEntry<T> entry, bool notify, string message, AceAdvancedSettingsWrapper advancedSettings) public async Task<(bool, string)> SetAceObjectAsync<T>(List<AceWrapper> aceWrappers, FileEntry<T> entry, bool notify, string message, AceAdvancedSettingsWrapper advancedSettings)
@ -233,8 +230,9 @@ public class FileSharingAceHelper
if (emailInvite) if (emailInvite)
{ {
var link = await _invitationLinkService.GetInvitationLinkAsync(w.Email, share, _authContext.CurrentAccount.ID); var link = await _invitationLinkService.GetInvitationLinkAsync(w.Email, share, _authContext.CurrentAccount.ID);
await _studioNotifyService.SendEmailRoomInviteAsync(w.Email, entry.Title, link); var shortenLink = await _urlShortener.GetShortenLinkAsync(link);
_logger.Debug(link);
await _studioNotifyService.SendEmailRoomInviteAsync(w.Email, entry.Title, shortenLink);
} }
if (w.Id == FileConstant.ShareLinkId) if (w.Id == FileConstant.ShareLinkId)
@ -439,6 +437,7 @@ public class FileSharing
private readonly FilesSettingsHelper _filesSettingsHelper; private readonly FilesSettingsHelper _filesSettingsHelper;
private readonly InvitationLinkService _invitationLinkService; private readonly InvitationLinkService _invitationLinkService;
private readonly ExternalShare _externalShare; private readonly ExternalShare _externalShare;
private readonly IUrlShortener _urlShortener;
public FileSharing( public FileSharing(
Global global, Global global,
@ -452,7 +451,8 @@ public class FileSharing
FileSharingHelper fileSharingHelper, FileSharingHelper fileSharingHelper,
FilesSettingsHelper filesSettingsHelper, FilesSettingsHelper filesSettingsHelper,
InvitationLinkService invitationLinkService, InvitationLinkService invitationLinkService,
ExternalShare externalShare) ExternalShare externalShare,
IUrlShortener urlShortener)
{ {
_global = global; _global = global;
_fileSecurity = fileSecurity; _fileSecurity = fileSecurity;
@ -466,6 +466,7 @@ public class FileSharing
_logger = logger; _logger = logger;
_invitationLinkService = invitationLinkService; _invitationLinkService = invitationLinkService;
_externalShare = externalShare; _externalShare = externalShare;
_urlShortener = urlShortener;
} }
public async Task<bool> CanSetAccessAsync<T>(FileEntry<T> entry) public async Task<bool> CanSetAccessAsync<T>(FileEntry<T> entry)
@ -564,9 +565,11 @@ public class FileSharing
continue; continue;
} }
w.Link = r.SubjectType == SubjectType.InvitationLink ? var link = r.SubjectType == SubjectType.InvitationLink
_invitationLinkService.GetInvitationLink(r.Subject, _authContext.CurrentAccount.ID) : ? _invitationLinkService.GetInvitationLink(r.Subject, _authContext.CurrentAccount.ID)
await _externalShare.GetLinkAsync(r.Subject); : await _externalShare.GetLinkAsync(r.Subject);
w.Link = await _urlShortener.GetShortenLinkAsync(link);
w.SubjectGroup = true; w.SubjectGroup = true;
w.CanEditAccess = false; w.CanEditAccess = false;
w.FileShareOptions.Password = await _externalShare.GetPasswordAsync(w.FileShareOptions.Password); w.FileShareOptions.Password = await _externalShare.GetPasswordAsync(w.FileShareOptions.Password);

View File

@ -24,8 +24,6 @@
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0 // 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 // International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
using Microsoft.AspNetCore.RateLimiting;
namespace ASC.People.Api; namespace ASC.People.Api;
public class UserController : PeopleControllerBase public class UserController : PeopleControllerBase
@ -65,6 +63,7 @@ public class UserController : PeopleControllerBase
private readonly UsersQuotaSyncOperation _usersQuotaSyncOperation; private readonly UsersQuotaSyncOperation _usersQuotaSyncOperation;
private readonly CountUserChecker _countUserChecker; private readonly CountUserChecker _countUserChecker;
private readonly UsersInRoomChecker _usersInRoomChecker; private readonly UsersInRoomChecker _usersInRoomChecker;
private readonly IUrlShortener _urlShortener;
public UserController( public UserController(
ICache cache, ICache cache,
@ -105,7 +104,8 @@ public class UserController : PeopleControllerBase
CountPaidUserChecker countPaidUserChecker, CountPaidUserChecker countPaidUserChecker,
CountUserChecker activeUsersChecker, CountUserChecker activeUsersChecker,
UsersInRoomChecker usersInRoomChecker, UsersInRoomChecker usersInRoomChecker,
IQuotaService quotaService) IQuotaService quotaService,
IUrlShortener urlShortener)
: base(userManager, permissionContext, apiContext, userPhotoManager, httpClientFactory, httpContextAccessor) : base(userManager, permissionContext, apiContext, userPhotoManager, httpClientFactory, httpContextAccessor)
{ {
_cache = cache; _cache = cache;
@ -141,6 +141,7 @@ public class UserController : PeopleControllerBase
_usersInRoomChecker = usersInRoomChecker; _usersInRoomChecker = usersInRoomChecker;
_quotaService = quotaService; _quotaService = quotaService;
_usersQuotaSyncOperation = usersQuotaSyncOperation; _usersQuotaSyncOperation = usersQuotaSyncOperation;
_urlShortener = urlShortener;
} }
/// <summary> /// <summary>
@ -363,9 +364,9 @@ public class UserController : PeopleControllerBase
var user = await _userManagerWrapper.AddInvitedUserAsync(invite.Email, invite.Type); var user = await _userManagerWrapper.AddInvitedUserAsync(invite.Email, invite.Type);
var link = await _invitationLinkService.GetInvitationLinkAsync(user.Email, invite.Type, _authContext.CurrentAccount.ID); var link = await _invitationLinkService.GetInvitationLinkAsync(user.Email, invite.Type, _authContext.CurrentAccount.ID);
var shortenLink = await _urlShortener.GetShortenLinkAsync(link);
await _studioNotifyService.SendDocSpaceInviteAsync(user.Email, link); await _studioNotifyService.SendDocSpaceInviteAsync(user.Email, shortenLink);
_logger.Debug(link);
} }
var result = new List<EmployeeDto>(); var result = new List<EmployeeDto>();
@ -391,6 +392,7 @@ public class UserController : PeopleControllerBase
/// <path>api/2.0/people/{userid}/password</path> /// <path>api/2.0/people/{userid}/password</path>
/// <httpMethod>PUT</httpMethod> /// <httpMethod>PUT</httpMethod>
[HttpPut("{userid}/password")] [HttpPut("{userid}/password")]
[EnableRateLimiting("sensitive_api")]
[Authorize(AuthenticationSchemes = "confirm", Roles = "PasswordChange,EmailChange,Activation,EmailActivation,Everyone")] [Authorize(AuthenticationSchemes = "confirm", Roles = "PasswordChange,EmailChange,Activation,EmailActivation,Everyone")]
public async Task<EmployeeFullDto> ChangeUserPassword(Guid userid, MemberRequestDto inDto) public async Task<EmployeeFullDto> ChangeUserPassword(Guid userid, MemberRequestDto inDto)
{ {
@ -1054,7 +1056,9 @@ public class UserController : PeopleControllerBase
} }
var link = await _invitationLinkService.GetInvitationLinkAsync(user.Email, type, _authContext.CurrentAccount.ID); var link = await _invitationLinkService.GetInvitationLinkAsync(user.Email, type, _authContext.CurrentAccount.ID);
await _studioNotifyService.SendDocSpaceInviteAsync(user.Email, link); var shortenLink = await _urlShortener.GetShortenLinkAsync(link);
await _studioNotifyService.SendDocSpaceInviteAsync(user.Email, shortenLink);
} }
else else
{ {

View File

@ -75,6 +75,7 @@ global using ASC.Web.Core.Mobile;
global using ASC.Web.Core.PublicResources; global using ASC.Web.Core.PublicResources;
global using ASC.Web.Core.Quota; global using ASC.Web.Core.Quota;
global using ASC.Web.Core.Users; global using ASC.Web.Core.Users;
global using ASC.Web.Core.Utility;
global using ASC.Web.Files; global using ASC.Web.Files;
global using ASC.Web.Studio.Core; global using ASC.Web.Studio.Core;
global using ASC.Web.Studio.Core.Notify; global using ASC.Web.Studio.Core.Notify;
@ -84,6 +85,7 @@ global using Autofac;
global using Microsoft.AspNetCore.Http.Extensions; global using Microsoft.AspNetCore.Http.Extensions;
global using Microsoft.AspNetCore.Mvc; global using Microsoft.AspNetCore.Mvc;
global using Microsoft.AspNetCore.RateLimiting;
global using Microsoft.EntityFrameworkCore; global using Microsoft.EntityFrameworkCore;
global using Microsoft.Extensions.Hosting.WindowsServices; global using Microsoft.Extensions.Hosting.WindowsServices;

View File

@ -197,8 +197,10 @@ public class PortalController : ControllerBase
return string.Empty; return string.Empty;
} }
return await _commonLinkUtility.GetConfirmationEmailUrlAsync(string.Empty, ConfirmType.LinkInvite, (int)employeeType, _authContext.CurrentAccount.ID) var link = await _commonLinkUtility.GetConfirmationEmailUrlAsync(string.Empty, ConfirmType.LinkInvite, (int)employeeType, _authContext.CurrentAccount.ID)
+ $"&emplType={employeeType:d}"; + $"&emplType={employeeType:d}";
return await _urlShortener.GetShortenLinkAsync(link);
} }
/// <summary> /// <summary>