/* * * (c) Copyright Ascensio System Limited 2010-2018 * * This program is freeware. You can redistribute it and/or modify it under the terms of the GNU * General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html). * In accordance with Section 7(a) of the GNU GPL 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 more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html * * You can contact Ascensio System SIA by email at sales@onlyoffice.com * * The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display * Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3. * * Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains * relevant author attributions when distributing the software. If the display of the logo in its graphic * form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE" * in every copy of the program you distribute. * Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks. * */ using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Net; using System.Text; using System.Text.RegularExpressions; using ASC.ApiSystem.Classes; using ASC.ApiSystem.Interfaces; using ASC.ApiSystem.Models; using ASC.Common; using ASC.Common.Logging; using ASC.Common.Utils; using ASC.Core; using ASC.Core.Common.Settings; using ASC.Core.Tenants; using ASC.Core.Users; using ASC.Security.Cryptography; using ASC.Web.Core.Helpers; using ASC.Web.Core.Users; using ASC.Web.Studio.Utility; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Options; using Newtonsoft.Json.Linq; namespace ASC.ApiSystem.Controllers { public class CommonMethods { public IHttpContextAccessor HttpContextAccessor { get; } private IConfiguration Configuration { get; } private ILog Log { get; } private CoreSettings CoreSettings { get; } private CommonLinkUtility CommonLinkUtility { get; } private EmailValidationKeyProvider EmailValidationKeyProvider { get; } private TimeZoneConverter TimeZoneConverter { get; } private CommonConstants CommonConstants { get; } private HostedSolution HostedSolution { get; } private IMemoryCache MemoryCache { get; } public CommonMethods( IHttpContextAccessor httpContextAccessor, IConfiguration configuration, IOptionsMonitor option, CoreSettings coreSettings, CommonLinkUtility commonLinkUtility, EmailValidationKeyProvider emailValidationKeyProvider, TimeZoneConverter timeZoneConverter, CommonConstants commonConstants, IMemoryCache memoryCache, IOptionsSnapshot hostedSolutionOptions) { HttpContextAccessor = httpContextAccessor; Configuration = configuration; Log = option.Get("ASC.ApiSystem"); CoreSettings = coreSettings; CommonLinkUtility = commonLinkUtility; EmailValidationKeyProvider = emailValidationKeyProvider; TimeZoneConverter = timeZoneConverter; CommonConstants = commonConstants; MemoryCache = memoryCache; HostedSolution = hostedSolutionOptions.Get(CommonConstants.BaseDbConnKeyString); } public object ToTenantWrapper(Tenant t) { return new { created = t.CreatedDateTime, domain = t.GetTenantDomain(CoreSettings), hostedRegion = t.HostedRegion, industry = t.Industry, language = t.Language, name = t.Name, ownerId = t.OwnerId, partnerId = t.PartnerId, paymentId = t.PaymentId, portalName = t.TenantAlias, status = t.Status.ToString(), tenantId = t.TenantId, timeZoneName = TimeZoneConverter.GetTimeZone(t.TimeZone).DisplayName, }; } public string CreateReference(string requestUriScheme, string tenantDomain, string email, bool first = false, string module = "", bool sms = false) { return string.Format("{0}{1}{2}/{3}{4}{5}{6}", requestUriScheme, Uri.SchemeDelimiter, tenantDomain, CommonLinkUtility.GetConfirmationUrlRelative(email, ConfirmType.Auth, (first ? "true" : "") + module + (sms ? "true" : "")), first ? "&first=true" : "", string.IsNullOrEmpty(module) ? "" : "&module=" + module, sms ? "&sms=true" : "" ); } public bool SendCongratulations(string requestUriScheme, Tenant tenant, bool skipWelcome, out string url) { var validationKey = EmailValidationKeyProvider.GetEmailKey(tenant.TenantId, tenant.OwnerId.ToString() + ConfirmType.Auth); url = string.Format("{0}{1}{2}{3}{4}?userid={5}&key={6}", requestUriScheme, Uri.SchemeDelimiter, tenant.GetTenantDomain(CoreSettings), CommonConstants.WebApiBaseUrl, "portal/sendcongratulations", tenant.OwnerId, validationKey); if (skipWelcome) { Log.DebugFormat("congratulations skiped"); return false; } var webRequest = (HttpWebRequest)WebRequest.Create(url); webRequest.Method = WebRequestMethods.Http.Post; webRequest.Accept = "application/x-www-form-urlencoded"; webRequest.ContentLength = 0; try { using var response = webRequest.GetResponse(); using var stream = response.GetResponseStream(); using var reader = new StreamReader(stream, Encoding.UTF8); var result = reader.ReadToEnd(); Log.DebugFormat("congratulations result = {0}", result); var resObj = JObject.Parse(result); if (resObj["errors"] != null && resObj["errors"].HasValues) { throw new Exception(result); } } catch (Exception ex) { Log.Error("SendCongratulations error", ex); return false; } url = null; return true; } public bool GetTenant(IModel model, out Tenant tenant) { if (model != null && model.TenantId.HasValue) { tenant = HostedSolution.GetTenant(model.TenantId.Value); return true; } if (model != null && !string.IsNullOrEmpty((model.PortalName ?? "").Trim())) { tenant = HostedSolution.GetTenant((model.PortalName ?? "").Trim()); return true; } tenant = null; return false; } public bool IsTestEmail(string email) { var regex = new Regex(CommonConstants.AutotestSecretEmails, RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.Compiled); return regex.IsMatch((email ?? "").ToLower()); } public bool CheckMuchRegistration(TenantModel model, string clientIP, Stopwatch sw) { if (IsTestEmail(model.Email)) return false; Log.DebugFormat("clientIP = {0}", clientIP); var cacheKey = "ip_" + clientIP; if (MemoryCache.TryGetValue(cacheKey, out int ipAttemptsCount)) { MemoryCache.Remove(cacheKey); } ipAttemptsCount++; MemoryCache.Set( // String that represents the name of the cache item, // could be any string cacheKey, // Something to store in the cache 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 SlidingExpiration = CommonConstants.MaxAttemptsTimeInterval, // Cache will not be removed before expired Priority = CacheItemPriority.NeverRemove }); if (ipAttemptsCount <= CommonConstants.MaxAttemptsCount) return false; Log.DebugFormat("PortalName = {0}; Too much reqests from ip: {1}", model.PortalName, clientIP); sw.Stop(); return true; } public string GetClientIp() { return HttpContextAccessor.HttpContext.Connection.RemoteIpAddress.ToString(); //TODO: check old version //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, string ip) { try { var data = string.Format("secret={0}&remoteip={1}&response={2}", Configuration["recaptcha:private-key"], ip, response); var url = Configuration["recaptcha:verify-url"] ?? "https://www.google.com/recaptcha/api/siteverify"; var webRequest = (HttpWebRequest)WebRequest.Create(url); webRequest.Method = WebRequestMethods.Http.Post; webRequest.ContentType = "application/x-www-form-urlencoded"; webRequest.ContentLength = data.Length; using (var writer = new StreamWriter(webRequest.GetRequestStream())) { writer.Write(data); } using var webResponse = webRequest.GetResponse(); using var reader = new StreamReader(webResponse.GetResponseStream()); var resp = reader.ReadToEnd(); var resObj = JObject.Parse(resp); if (resObj["success"] != null && resObj.Value("success")) { return true; } else { Log.DebugFormat("Recaptcha error: {0}", resp); } if (resObj["error-codes"] != null && resObj["error-codes"].HasValues) { Log.DebugFormat("Recaptcha api returns errors: {0}", resp); } } catch (Exception ex) { Log.Error(ex); } return false; } } public static class CommonMethodsExtention { public static DIHelper AddCommonMethods(this DIHelper services) { if (services.TryAddScoped()) { return services .AddCoreSettingsService() .AddCommonLinkUtilityService() .AddEmailValidationKeyProviderService() .AddApiSystemHelper() .AddTenantManagerService() .AddUserFormatter() .AddUserManagerWrapperService() .AddSettingsManagerService() .AddSecurityContextService() .AddHostedSolutionService(); } return services; } } }