2022-10-19 11:18:52 +00:00
|
|
|
// (c) Copyright Ascensio System SIA 2010-2022
|
|
|
|
//
|
|
|
|
// 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
|
|
|
|
|
2022-04-22 13:24:54 +00:00
|
|
|
namespace ASC.ApiSystem.Controllers;
|
2022-10-19 11:18:52 +00:00
|
|
|
|
2022-04-22 13:24:54 +00:00
|
|
|
[Scope]
|
|
|
|
public class CommonMethods
|
|
|
|
{
|
2022-10-14 14:52:00 +00:00
|
|
|
private readonly IHttpContextAccessor _httpContextAccessor;
|
|
|
|
private readonly IConfiguration _configuration;
|
|
|
|
private readonly ILogger<CommonMethods> _log;
|
|
|
|
private readonly CoreSettings _coreSettings;
|
|
|
|
private readonly CommonLinkUtility _commonLinkUtility;
|
|
|
|
private readonly EmailValidationKeyProvider _emailValidationKeyProvider;
|
|
|
|
private readonly TimeZoneConverter _timeZoneConverter;
|
|
|
|
private readonly CommonConstants _commonConstants;
|
|
|
|
private readonly HostedSolution _hostedSolution;
|
2022-10-19 11:18:52 +00:00
|
|
|
private readonly IMemoryCache _memoryCache;
|
|
|
|
private readonly CoreBaseSettings _coreBaseSettings;
|
|
|
|
private readonly TenantManager _tenantManager;
|
2022-10-14 14:52:00 +00:00
|
|
|
private readonly IHttpClientFactory _clientFactory;
|
2022-04-22 13:24:54 +00:00
|
|
|
|
2022-10-19 11:18:52 +00:00
|
|
|
public CommonMethods(
|
|
|
|
IHttpContextAccessor httpContextAccessor,
|
|
|
|
IConfiguration configuration,
|
|
|
|
ILogger<CommonMethods> log,
|
|
|
|
CoreSettings coreSettings,
|
|
|
|
CommonLinkUtility commonLinkUtility,
|
|
|
|
EmailValidationKeyProvider emailValidationKeyProvider,
|
|
|
|
TimeZoneConverter timeZoneConverter, CommonConstants commonConstants,
|
|
|
|
IMemoryCache memoryCache,
|
|
|
|
HostedSolution hostedSolution,
|
|
|
|
CoreBaseSettings coreBaseSettings,
|
2022-04-22 13:24:54 +00:00
|
|
|
TenantManager tenantManager,
|
|
|
|
IHttpClientFactory clientFactory)
|
|
|
|
{
|
2022-10-14 14:52:00 +00:00
|
|
|
_httpContextAccessor = httpContextAccessor;
|
|
|
|
_configuration = configuration;
|
|
|
|
_log = log;
|
|
|
|
_coreSettings = coreSettings;
|
|
|
|
_commonLinkUtility = commonLinkUtility;
|
|
|
|
_emailValidationKeyProvider = emailValidationKeyProvider;
|
|
|
|
_timeZoneConverter = timeZoneConverter;
|
|
|
|
_commonConstants = commonConstants;
|
2022-10-19 11:18:52 +00:00
|
|
|
_memoryCache = memoryCache;
|
|
|
|
_coreBaseSettings = coreBaseSettings;
|
|
|
|
_tenantManager = tenantManager;
|
2022-10-14 14:52:00 +00:00
|
|
|
_clientFactory = clientFactory;
|
2022-10-19 11:18:52 +00:00
|
|
|
_hostedSolution = hostedSolution;
|
2022-10-14 14:52:00 +00:00
|
|
|
_hostedSolution.Init(CommonConstants.BaseDbConnKeyString);
|
2022-10-19 11:18:52 +00:00
|
|
|
}
|
2020-02-18 13:48:38 +00:00
|
|
|
|
2022-04-22 13:24:54 +00:00
|
|
|
public object ToTenantWrapper(Tenant t)
|
|
|
|
{
|
|
|
|
return new
|
2020-02-18 13:48:38 +00:00
|
|
|
{
|
2022-04-22 13:24:54 +00:00
|
|
|
created = t.CreationDateTime,
|
2022-10-14 14:52:00 +00:00
|
|
|
domain = t.GetTenantDomain(_coreSettings),
|
2022-04-22 13:24:54 +00:00
|
|
|
hostedRegion = t.HostedRegion,
|
|
|
|
industry = t.Industry,
|
|
|
|
language = t.Language,
|
2022-10-05 11:23:53 +00:00
|
|
|
name = t.Name == "" ? Resource.PortalName : t.Name,
|
2022-04-22 13:24:54 +00:00
|
|
|
ownerId = t.OwnerId,
|
|
|
|
paymentId = t.PaymentId,
|
|
|
|
portalName = t.Alias,
|
|
|
|
status = t.Status.ToString(),
|
|
|
|
tenantId = t.Id,
|
2022-10-14 14:52:00 +00:00
|
|
|
timeZoneName = _timeZoneConverter.GetTimeZone(t.TimeZone).DisplayName,
|
2022-04-22 13:24:54 +00:00
|
|
|
};
|
2022-10-19 11:18:52 +00:00
|
|
|
}
|
2020-02-18 13:48:38 +00:00
|
|
|
|
2022-11-10 15:07:11 +00:00
|
|
|
public string CreateReference(int tenantId,string requestUriScheme, string tenantDomain, string email, bool first = false, string module = "", bool sms = false)
|
2022-04-22 13:24:54 +00:00
|
|
|
{
|
2022-11-10 15:07:11 +00:00
|
|
|
var url = _commonLinkUtility.GetConfirmationUrlRelative(tenantId, email, ConfirmType.Auth, (first ? "true" : "") + module + (sms ? "true" : ""));
|
2022-04-22 13:24:54 +00:00
|
|
|
return $"{requestUriScheme}{Uri.SchemeDelimiter}{tenantDomain}/{url}{(first ? "&first=true" : "")}{(string.IsNullOrEmpty(module) ? "" : "&module=" + module)}{(sms ? "&sms=true" : "")}";
|
|
|
|
}
|
2020-02-18 13:48:38 +00:00
|
|
|
|
2022-04-22 13:24:54 +00:00
|
|
|
public bool SendCongratulations(string requestUriScheme, Tenant tenant, bool skipWelcome, out string url)
|
|
|
|
{
|
2022-10-14 14:52:00 +00:00
|
|
|
var validationKey = _emailValidationKeyProvider.GetEmailKey(tenant.Id, tenant.OwnerId.ToString() + ConfirmType.Auth);
|
2022-04-22 13:24:54 +00:00
|
|
|
|
|
|
|
url = string.Format("{0}{1}{2}{3}{4}?userid={5}&key={6}",
|
|
|
|
requestUriScheme,
|
|
|
|
Uri.SchemeDelimiter,
|
2022-10-14 14:52:00 +00:00
|
|
|
tenant.GetTenantDomain(_coreSettings),
|
|
|
|
_commonConstants.WebApiBaseUrl,
|
2022-04-22 13:24:54 +00:00
|
|
|
"portal/sendcongratulations",
|
|
|
|
tenant.OwnerId,
|
|
|
|
validationKey);
|
|
|
|
|
|
|
|
if (skipWelcome)
|
2020-02-18 13:48:38 +00:00
|
|
|
{
|
2022-10-14 14:52:00 +00:00
|
|
|
_log.LogDebug("congratulations skiped");
|
2022-04-22 13:24:54 +00:00
|
|
|
return false;
|
|
|
|
}
|
2022-10-19 11:18:52 +00:00
|
|
|
|
|
|
|
var request = new HttpRequestMessage
|
|
|
|
{
|
|
|
|
Method = HttpMethod.Post,
|
|
|
|
RequestUri = new Uri(url)
|
|
|
|
};
|
2022-11-11 08:53:11 +00:00
|
|
|
request.Headers.Accept.Add(MediaTypeWithQualityHeaderValue.Parse("application/json"));
|
2020-02-18 13:48:38 +00:00
|
|
|
|
2022-04-22 13:24:54 +00:00
|
|
|
try
|
2022-10-19 11:18:52 +00:00
|
|
|
{
|
2022-10-14 14:52:00 +00:00
|
|
|
var httpClient = _clientFactory.CreateClient();
|
2022-10-19 11:18:52 +00:00
|
|
|
using var response = httpClient.Send(request);
|
2020-02-18 13:48:38 +00:00
|
|
|
|
2022-11-11 08:53:11 +00:00
|
|
|
_log.LogDebug("congratulations result = {0}", response.StatusCode);
|
2020-02-18 13:48:38 +00:00
|
|
|
|
2022-11-11 08:53:11 +00:00
|
|
|
if (response.StatusCode != HttpStatusCode.OK)
|
2020-02-18 13:48:38 +00:00
|
|
|
{
|
2022-11-11 08:53:11 +00:00
|
|
|
using var stream = response.Content.ReadAsStream();
|
|
|
|
using var reader = new StreamReader(stream, Encoding.UTF8);
|
|
|
|
var result = reader.ReadToEnd();
|
2022-04-22 13:24:54 +00:00
|
|
|
throw new Exception(result);
|
2020-02-18 13:48:38 +00:00
|
|
|
}
|
|
|
|
}
|
2022-04-22 13:24:54 +00:00
|
|
|
catch (Exception ex)
|
|
|
|
{
|
2022-10-14 14:52:00 +00:00
|
|
|
_log.LogError(ex, "SendCongratulations error");
|
2020-02-18 13:48:38 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-04-22 13:24:54 +00:00
|
|
|
url = null;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
public bool GetTenant(IModel model, out Tenant tenant)
|
2022-10-19 11:18:52 +00:00
|
|
|
{
|
2022-10-14 14:52:00 +00:00
|
|
|
if (_coreBaseSettings.Standalone && model != null && !string.IsNullOrWhiteSpace((model.PortalName ?? "")))
|
2022-10-19 11:18:52 +00:00
|
|
|
{
|
|
|
|
tenant = _tenantManager.GetTenant((model.PortalName ?? "").Trim());
|
|
|
|
return true;
|
|
|
|
}
|
2022-04-22 13:24:54 +00:00
|
|
|
|
|
|
|
if (model != null && model.TenantId.HasValue)
|
|
|
|
{
|
2022-10-14 14:52:00 +00:00
|
|
|
tenant = _hostedSolution.GetTenant(model.TenantId.Value);
|
2022-04-22 13:24:54 +00:00
|
|
|
return true;
|
2020-02-18 13:48:38 +00:00
|
|
|
}
|
|
|
|
|
2022-04-22 13:24:54 +00:00
|
|
|
if (model != null && !string.IsNullOrWhiteSpace((model.PortalName ?? "")))
|
2020-02-18 13:48:38 +00:00
|
|
|
{
|
2022-10-14 14:52:00 +00:00
|
|
|
tenant = _hostedSolution.GetTenant((model.PortalName ?? "").Trim());
|
2022-04-22 13:24:54 +00:00
|
|
|
return true;
|
|
|
|
}
|
2020-02-18 13:48:38 +00:00
|
|
|
|
2022-04-22 13:24:54 +00:00
|
|
|
tenant = null;
|
|
|
|
return false;
|
|
|
|
}
|
2020-02-18 13:48:38 +00:00
|
|
|
|
2022-04-22 13:24:54 +00:00
|
|
|
public bool IsTestEmail(string email)
|
2022-10-19 11:18:52 +00:00
|
|
|
{
|
|
|
|
//the point is not needed in gmail.com
|
|
|
|
email = Regex.Replace(email ?? "", "\\.*(?=\\S*(@gmail.com$))", "").ToLower();
|
|
|
|
if (string.IsNullOrEmpty(email) || string.IsNullOrEmpty(_commonConstants.AutotestSecretEmails))
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
var regex = new Regex(_commonConstants.AutotestSecretEmails, RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.Compiled);
|
2022-04-22 13:24:54 +00:00
|
|
|
return regex.IsMatch(email);
|
|
|
|
}
|
2020-02-18 13:48:38 +00:00
|
|
|
|
2022-04-22 13:24:54 +00:00
|
|
|
public bool CheckMuchRegistration(TenantModel model, string clientIP, Stopwatch sw)
|
|
|
|
{
|
2022-10-19 11:18:52 +00:00
|
|
|
if (IsTestEmail(model.Email))
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-10-14 14:52:00 +00:00
|
|
|
_log.LogDebug("clientIP = {0}", clientIP);
|
2020-02-18 13:48:38 +00:00
|
|
|
|
2022-04-22 13:24:54 +00:00
|
|
|
var cacheKey = "ip_" + clientIP;
|
2020-02-18 13:48:38 +00:00
|
|
|
|
2022-10-14 14:52:00 +00:00
|
|
|
if (_memoryCache.TryGetValue(cacheKey, out int ipAttemptsCount))
|
2020-02-18 13:48:38 +00:00
|
|
|
{
|
2022-10-14 14:52:00 +00:00
|
|
|
_memoryCache.Remove(cacheKey);
|
2022-04-22 13:24:54 +00:00
|
|
|
}
|
2020-02-18 13:48:38 +00:00
|
|
|
|
2022-04-22 13:24:54 +00:00
|
|
|
ipAttemptsCount++;
|
2020-02-18 13:48:38 +00:00
|
|
|
|
2022-10-19 11:18:52 +00:00
|
|
|
_memoryCache.Set(
|
|
|
|
// String that represents the name of the cache item,
|
|
|
|
// could be any string
|
|
|
|
cacheKey,
|
|
|
|
// Something to store in the cache
|
2022-04-22 13:24:54 +00:00
|
|
|
ipAttemptsCount,
|
|
|
|
new MemoryCacheEntryOptions
|
|
|
|
{
|
|
|
|
// Will not use absolute cache expiration
|
|
|
|
AbsoluteExpiration = DateTime.MaxValue,
|
|
|
|
// Cache will expire after one hour
|
|
|
|
// You can change this time interval according
|
|
|
|
// to your requriements
|
2022-10-14 14:52:00 +00:00
|
|
|
SlidingExpiration = _commonConstants.MaxAttemptsTimeInterval,
|
2022-04-22 13:24:54 +00:00
|
|
|
// Cache will not be removed before expired
|
|
|
|
Priority = CacheItemPriority.NeverRemove
|
|
|
|
});
|
|
|
|
|
2022-10-19 11:18:52 +00:00
|
|
|
if (ipAttemptsCount <= _commonConstants.MaxAttemptsCount)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-10-14 14:52:00 +00:00
|
|
|
_log.LogDebug("PortalName = {0}; Too much reqests from ip: {1}", model.PortalName, clientIP);
|
2022-04-22 13:24:54 +00:00
|
|
|
sw.Stop();
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2020-02-18 13:48:38 +00:00
|
|
|
|
2022-04-22 13:24:54 +00:00
|
|
|
public string GetClientIp()
|
|
|
|
{
|
2022-10-14 14:52:00 +00:00
|
|
|
return _httpContextAccessor.HttpContext.Connection.RemoteIpAddress.ToString();
|
2020-02-18 13:48:38 +00:00
|
|
|
|
2022-04-22 13:24:54 +00:00
|
|
|
//TODO: check old version
|
2020-02-18 13:48:38 +00:00
|
|
|
|
2022-04-22 13:24:54 +00:00
|
|
|
//if (request.Properties.ContainsKey("MS_HttpContext"))
|
|
|
|
//{
|
|
|
|
// return ((HttpContextWrapper)request.Properties["MS_HttpContext"]).Request.UserHostAddress;
|
|
|
|
//}
|
|
|
|
|
|
|
|
//if (request.Properties.ContainsKey(RemoteEndpointMessageProperty.Name))
|
|
|
|
//{
|
|
|
|
// var prop = (RemoteEndpointMessageProperty)request.Properties[RemoteEndpointMessageProperty.Name];
|
|
|
|
// return prop.Address;
|
|
|
|
//}
|
|
|
|
|
|
|
|
//return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
public bool ValidateRecaptcha(string response, RecaptchaType recaptchaType, string ip)
|
|
|
|
{
|
|
|
|
try
|
2022-10-19 11:18:52 +00:00
|
|
|
{
|
|
|
|
string privateKey;
|
|
|
|
switch (recaptchaType)
|
|
|
|
{
|
|
|
|
case RecaptchaType.AndroidV2:
|
|
|
|
privateKey = _configuration["recaptcha:private-key:android"];
|
|
|
|
break;
|
|
|
|
case RecaptchaType.iOSV2:
|
|
|
|
privateKey = _configuration["recaptcha:private-key:ios"];
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
privateKey = _configuration["recaptcha:private-key:default"];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2022-04-22 13:24:54 +00:00
|
|
|
var data = $"secret={privateKey}&remoteip={ip}&response={response}";
|
2022-10-14 14:52:00 +00:00
|
|
|
var url = _configuration["recaptcha:verify-url"] ?? "https://www.recaptcha.net/recaptcha/api/siteverify";
|
2022-10-19 11:18:52 +00:00
|
|
|
|
|
|
|
var request = new HttpRequestMessage
|
|
|
|
{
|
|
|
|
RequestUri = new Uri(url),
|
|
|
|
Method = HttpMethod.Post,
|
|
|
|
Content = new StringContent(data, Encoding.UTF8, "application/x-www-form-urlencoded")
|
|
|
|
};
|
|
|
|
|
2022-10-14 14:52:00 +00:00
|
|
|
var httpClient = _clientFactory.CreateClient();
|
2022-10-19 11:18:52 +00:00
|
|
|
using var httpClientResponse = httpClient.Send(request);
|
2022-04-22 13:24:54 +00:00
|
|
|
using var stream = httpClientResponse.Content.ReadAsStream();
|
2022-10-19 11:18:52 +00:00
|
|
|
using var reader = new StreamReader(stream);
|
2022-04-22 13:24:54 +00:00
|
|
|
|
|
|
|
var resp = reader.ReadToEnd();
|
|
|
|
var resObj = JObject.Parse(resp);
|
|
|
|
|
|
|
|
if (resObj["success"] != null && resObj.Value<bool>("success"))
|
|
|
|
{
|
|
|
|
return true;
|
2020-02-18 13:48:38 +00:00
|
|
|
}
|
2022-04-22 13:24:54 +00:00
|
|
|
else
|
2020-02-18 13:48:38 +00:00
|
|
|
{
|
2022-10-14 14:52:00 +00:00
|
|
|
_log.LogDebug("Recaptcha error: {0}", resp);
|
2020-02-18 13:48:38 +00:00
|
|
|
}
|
2022-04-22 13:24:54 +00:00
|
|
|
|
|
|
|
if (resObj["error-codes"] != null && resObj["error-codes"].HasValues)
|
|
|
|
{
|
2022-10-14 14:52:00 +00:00
|
|
|
_log.LogDebug("Recaptcha api returns errors: {0}", resp);
|
2022-04-22 13:24:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (Exception ex)
|
|
|
|
{
|
2022-10-14 14:52:00 +00:00
|
|
|
_log.LogError(ex, "ValidateRecaptcha");
|
2020-02-18 13:48:38 +00:00
|
|
|
}
|
2022-04-22 13:24:54 +00:00
|
|
|
return false;
|
2020-02-18 13:48:38 +00:00
|
|
|
}
|
2022-04-22 13:24:54 +00:00
|
|
|
}
|