/* * * (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.Globalization; using System.IO; using System.Linq; using System.Text.RegularExpressions; using System.Threading; using ASC.Common; using ASC.Common.Logging; using ASC.Common.Notify.Engine; using ASC.Core; using ASC.Core.Common.Settings; using ASC.Core.Tenants; using ASC.Core.Users; using ASC.Notify; using ASC.Notify.Engine; using ASC.Notify.Messages; using ASC.Notify.Patterns; using ASC.Notify.Textile; using ASC.Web.Core; using ASC.Web.Core.Users; using ASC.Web.Core.WhiteLabel; using ASC.Web.Studio.Utility; using Google.Protobuf; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using MimeKit.Utils; namespace ASC.Web.Studio.Core.Notify { public static class NotifyConfiguration { private static bool configured; private static readonly object locker = new object(); private static readonly Regex urlReplacer = new Regex(@"(]*href=(('(?[^>']*)')|(""(?[^>""]*)""))[^>]*>)|(]*src=(('(?(?![data:|cid:])[^>']*)')|(""(?(?![data:|cid:])[^>""]*)""))[^/>]*/?>)", RegexOptions.Compiled | RegexOptions.IgnoreCase); private static readonly Regex textileLinkReplacer = new Regex(@"""(?[\w\W]+?)"":""(?[^""]+)""", RegexOptions.Singleline | RegexOptions.Compiled); private static IServiceProvider ServiceProvider { get; set; } public static void Configure(IServiceProvider serviceProvider) { lock (locker) { if (!configured) { configured = true; ServiceProvider = serviceProvider; WorkContext.NotifyStartUp(serviceProvider); WorkContext.NotifyContext.NotifyClientRegistration += NotifyClientRegisterCallback; WorkContext.NotifyContext.NotifyEngine.BeforeTransferRequest += BeforeTransferRequest; } } } private static void NotifyClientRegisterCallback(Context context, INotifyClient client) { #region url correction var absoluteUrl = new SendInterceptorSkeleton( "Web.UrlAbsoluter", InterceptorPlace.MessageSend, InterceptorLifetime.Global, (r, p, scope) => { if (r != null && r.CurrentMessage != null && r.CurrentMessage.ContentType == Pattern.HTMLContentType) { var commonLinkUtility = scope.ServiceProvider.GetService(); var body = r.CurrentMessage.Body; body = urlReplacer.Replace(body, m => { var url = m.Groups["url"].Value; var ind = m.Groups["url"].Index - m.Index; return string.IsNullOrEmpty(url) && ind > 0 ? m.Value.Insert(ind, commonLinkUtility.GetFullAbsolutePath(string.Empty)) : m.Value.Replace(url, commonLinkUtility.GetFullAbsolutePath(url)); }); body = textileLinkReplacer.Replace(body, m => { var url = m.Groups["link"].Value; var ind = m.Groups["link"].Index - m.Index; return string.IsNullOrEmpty(url) && ind > 0 ? m.Value.Insert(ind, commonLinkUtility.GetFullAbsolutePath(string.Empty)) : m.Value.Replace(url, commonLinkUtility.GetFullAbsolutePath(url)); }); r.CurrentMessage.Body = body; } return false; }); client.AddInterceptor(absoluteUrl); #endregion #region security and culture var securityAndCulture = new SendInterceptorSkeleton( "ProductSecurityInterceptor", InterceptorPlace.DirectSend, InterceptorLifetime.Global, (r, p, scope) => { var scopeClass = scope.ServiceProvider.GetService(); try { // culture var u = Constants.LostUser; var tenant = scopeClass.TenantManager.GetCurrentTenant(); if (32 <= r.Recipient.ID.Length) { var guid = default(Guid); try { guid = new Guid(r.Recipient.ID); } catch (FormatException) { } catch (OverflowException) { } if (guid != default) { u = scopeClass.UserManager.GetUsers(guid); } } if (Constants.LostUser.Equals(u)) { u = scopeClass.UserManager.GetUserByEmail(r.Recipient.ID); } if (Constants.LostUser.Equals(u)) { u = scopeClass.UserManager.GetUserByUserName(r.Recipient.ID); } if (!Constants.LostUser.Equals(u)) { var culture = !string.IsNullOrEmpty(u.CultureName) ? u.GetCulture() : tenant.GetCulture(); Thread.CurrentThread.CurrentCulture = culture; Thread.CurrentThread.CurrentUICulture = culture; // security var tag = r.Arguments.Find(a => a.Tag == CommonTags.ModuleID); var productId = tag != null ? (Guid)tag.Value : Guid.Empty; if (productId == Guid.Empty) { tag = r.Arguments.Find(a => a.Tag == CommonTags.ProductID); productId = tag != null ? (Guid)tag.Value : Guid.Empty; } if (productId == Guid.Empty) { productId = (Guid)(CallContext.GetData("asc.web.product_id") ?? Guid.Empty); } if (productId != Guid.Empty && productId != new Guid("f4d98afdd336433287783c6945c81ea0") /* ignore people product */) { return !scopeClass.WebItemSecurity.IsAvailableForUser(productId, u.ID); } } var tagCulture = r.Arguments.FirstOrDefault(a => a.Tag == CommonTags.Culture); if (tagCulture != null) { var culture = CultureInfo.GetCultureInfo((string)tagCulture.Value); Thread.CurrentThread.CurrentCulture = culture; Thread.CurrentThread.CurrentUICulture = culture; } } catch (Exception error) { scopeClass.Options.CurrentValue.Error(error); } return false; }); client.AddInterceptor(securityAndCulture); #endregion #region white label correction var whiteLabel = new SendInterceptorSkeleton( "WhiteLabelInterceptor", InterceptorPlace.MessageSend, InterceptorLifetime.Global, (r, p, scope) => { try { var tags = r.Arguments; var logoTextTag = tags.FirstOrDefault(a => a.Tag == CommonTags.LetterLogoText); var logoText = logoTextTag != null ? (string)logoTextTag.Value : string.Empty; if (!string.IsNullOrEmpty(logoText)) { r.CurrentMessage.Body = r.CurrentMessage.Body .Replace(string.Format("${{{0}}}", CommonTags.LetterLogoText), logoText); } } catch (Exception error) { scope.ServiceProvider.GetService>().CurrentValue.Error(error); } return false; }); client.AddInterceptor(whiteLabel); #endregion } private static void BeforeTransferRequest(NotifyEngine sender, NotifyRequest request, IServiceScope serviceScope) { var aid = Guid.Empty; var aname = string.Empty; var tenant = serviceScope.ServiceProvider.GetService().GetCurrentTenant(); var authContext = serviceScope.ServiceProvider.GetService(); var userManager = serviceScope.ServiceProvider.GetService(); var displayUserSettingsHelper = serviceScope.ServiceProvider.GetService(); if (authContext.IsAuthenticated) { aid = authContext.CurrentAccount.ID; var user = userManager.GetUsers(aid); if (userManager.UserExists(user)) { aname = user.DisplayUserName(false, displayUserSettingsHelper) .Replace(">", ">") .Replace("<", "<"); } } using var scope = ServiceProvider.CreateScope(); var scopeClass = scope.ServiceProvider.GetService(); var log = scopeClass.Options.CurrentValue; scopeClass.CommonLinkUtility.GetLocationByRequest(out var product, out var module); if (product == null && CallContext.GetData("asc.web.product_id") != null) { product = scopeClass.WebItemManager[(Guid)CallContext.GetData("asc.web.product_id")] as IProduct; } var logoText = TenantWhiteLabelSettings.DefaultLogoText; if ((scopeClass.TenantExtra.Enterprise || scopeClass.CoreBaseSettings.CustomMode) && !MailWhiteLabelSettings.IsDefault(scopeClass.SettingsManager, scopeClass.Configuration)) { logoText = scopeClass.TenantLogoManager.GetLogoText(); } request.Arguments.Add(new TagValue(CommonTags.AuthorID, aid)); request.Arguments.Add(new TagValue(CommonTags.AuthorName, aname)); request.Arguments.Add(new TagValue(CommonTags.AuthorUrl, scopeClass.CommonLinkUtility.GetFullAbsolutePath(scopeClass.CommonLinkUtility.GetUserProfile(aid)))); request.Arguments.Add(new TagValue(CommonTags.VirtualRootPath, scopeClass.CommonLinkUtility.GetFullAbsolutePath("~").TrimEnd('/'))); request.Arguments.Add(new TagValue(CommonTags.ProductID, product != null ? product.ID : Guid.Empty)); request.Arguments.Add(new TagValue(CommonTags.ModuleID, module != null ? module.ID : Guid.Empty)); request.Arguments.Add(new TagValue(CommonTags.ProductUrl, scopeClass.CommonLinkUtility.GetFullAbsolutePath(product != null ? product.StartURL : "~"))); request.Arguments.Add(new TagValue(CommonTags.DateTime, scopeClass.TenantUtil.DateTimeNow())); request.Arguments.Add(new TagValue(CommonTags.RecipientID, Context.SYS_RECIPIENT_ID)); request.Arguments.Add(new TagValue(CommonTags.ProfileUrl, scopeClass.CommonLinkUtility.GetFullAbsolutePath(scopeClass.CommonLinkUtility.GetMyStaff()))); request.Arguments.Add(new TagValue(CommonTags.RecipientSubscriptionConfigURL, scopeClass.CommonLinkUtility.GetMyStaff())); request.Arguments.Add(new TagValue(CommonTags.HelpLink, scopeClass.CommonLinkUtility.GetHelpLink(scopeClass.SettingsManager, scopeClass.AdditionalWhiteLabelSettingsHelper, false))); request.Arguments.Add(new TagValue(CommonTags.LetterLogoText, logoText)); request.Arguments.Add(new TagValue(CommonTags.MailWhiteLabelSettings, MailWhiteLabelSettings.Instance(scopeClass.SettingsManager))); request.Arguments.Add(new TagValue(CommonTags.SendFrom, tenant.Name)); request.Arguments.Add(new TagValue(CommonTags.ImagePath, scopeClass.StudioNotifyHelper.GetNotificationImageUrl("").TrimEnd('/'))); AddLetterLogo(request, scopeClass.TenantExtra, scopeClass.TenantLogoManager, scopeClass.CoreBaseSettings, scopeClass.CommonLinkUtility, log); } private static void AddLetterLogo(NotifyRequest request, TenantExtra tenantExtra, TenantLogoManager tenantLogoManager, CoreBaseSettings coreBaseSettings, CommonLinkUtility commonLinkUtility, ILog Log) { if (tenantExtra.Enterprise || coreBaseSettings.CustomMode) { try { var logoData = tenantLogoManager.GetMailLogoDataFromCache(); if (logoData == null) { var logoStream = tenantLogoManager.GetWhitelabelMailLogo(); logoData = ReadStreamToByteArray(logoStream) ?? GetDefaultMailLogo(); if (logoData != null) tenantLogoManager.InsertMailLogoDataToCache(logoData); } if (logoData != null) { var attachment = new NotifyMessageAttachment { FileName = "logo.png", Content = ByteString.CopyFrom(logoData), ContentId = MimeUtils.GenerateMessageId() }; request.Arguments.Add(new TagValue(CommonTags.LetterLogo, "cid:" + attachment.ContentId)); request.Arguments.Add(new TagValue(CommonTags.EmbeddedAttachments, new[] { attachment })); return; } } catch (Exception error) { Log.Error(error); } } var logoUrl = commonLinkUtility.GetFullAbsolutePath(tenantLogoManager.GetLogoDark(true)); request.Arguments.Add(new TagValue(CommonTags.LetterLogo, logoUrl)); } private static byte[] ReadStreamToByteArray(Stream inputStream) { if (inputStream == null) return null; using (inputStream) { using var memoryStream = new MemoryStream(); inputStream.CopyTo(memoryStream); return memoryStream.ToArray(); } } public static byte[] GetDefaultMailLogo() { var filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "skins", "default", "images", "onlyoffice_logo", "dark_general.png"); return File.Exists(filePath) ? File.ReadAllBytes(filePath) : null; } class Scope { internal TenantManager TenantManager { get; } internal WebItemSecurity WebItemSecurity { get; } internal UserManager UserManager { get; } internal IOptionsMonitor Options { get; } internal TenantExtra TenantExtra { get; } internal WebItemManagerSecurity WebItemManagerSecurity { get; } internal WebItemManager WebItemManager { get; } internal IConfiguration Configuration { get; } internal TenantLogoManager TenantLogoManager { get; } internal AdditionalWhiteLabelSettingsHelper AdditionalWhiteLabelSettingsHelper { get; } internal TenantUtil TenantUtil { get; } internal CoreBaseSettings CoreBaseSettings { get; } internal CommonLinkUtility CommonLinkUtility { get; } internal SettingsManager SettingsManager { get; } internal StudioNotifyHelper StudioNotifyHelper { get; } public Scope(TenantManager tenantManager, WebItemSecurity webItemSecurity, UserManager userManager, IOptionsMonitor options, TenantExtra tenantExtra, WebItemManagerSecurity webItemManagerSecurity, WebItemManager webItemManager, IConfiguration configuration, TenantLogoManager tenantLogoManager, AdditionalWhiteLabelSettingsHelper additionalWhiteLabelSettingsHelper, TenantUtil tenantUtil, CoreBaseSettings coreBaseSettings, CommonLinkUtility commonLinkUtility, SettingsManager settingsManager, StudioNotifyHelper studioNotifyHelper ) { TenantManager = tenantManager; WebItemSecurity = webItemSecurity; UserManager = userManager; Options = options; TenantExtra = tenantExtra; WebItemManagerSecurity = webItemManagerSecurity; WebItemManager = webItemManager; Configuration = configuration; TenantLogoManager = tenantLogoManager; AdditionalWhiteLabelSettingsHelper = additionalWhiteLabelSettingsHelper; TenantUtil = tenantUtil; CoreBaseSettings = coreBaseSettings; CommonLinkUtility = commonLinkUtility; SettingsManager = settingsManager; StudioNotifyHelper = studioNotifyHelper; } } } public static class NotifyConfigurationExtension { public static DIHelper AddNotifyConfiguration(this DIHelper services) { return services .AddJabberStylerService() .AddTextileStylerService() .AddPushStylerService() .AddTenantManagerService() .AddAuthContextService() .AddUserManagerService() .AddDisplayUserSettingsService() .AddTenantExtraService() .AddWebItemManagerSecurity() .AddWebItemManager() .AddTenantLogoManagerService() .AddTenantUtilService() .AddCoreBaseSettingsService() .AddAdditionalWhiteLabelSettingsService() .AddCommonLinkUtilityService() .AddMailWhiteLabelSettingsService(); } } }