/* * * (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.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) => { try { //fix var tenantManager = scope.ServiceProvider.GetService(); var webItemSecurity = scope.ServiceProvider.GetService(); var userManager = scope.ServiceProvider.GetService(); // culture var u = Constants.LostUser; var tenant = 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 = userManager.GetUsers(guid); } } if (Constants.LostUser.Equals(u)) { u = userManager.GetUserByEmail(r.Recipient.ID); } if (Constants.LostUser.Equals(u)) { u = 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 !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) { scope.ServiceProvider.GetService>().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 tenantExtra = scope.ServiceProvider.GetService(); var webItemManagerSecurity = scope.ServiceProvider.GetService(); var webItemManager = scope.ServiceProvider.GetService(); var configuration = scope.ServiceProvider.GetService(); var tenantLogoManager = scope.ServiceProvider.GetService(); var additionalWhiteLabelSettingsHelper = scope.ServiceProvider.GetService(); var tenantUtil = scope.ServiceProvider.GetService(); var coreBaseSettings = scope.ServiceProvider.GetService(); var commonLinkUtility = scope.ServiceProvider.GetService(); var settingsManager = scope.ServiceProvider.GetService(); var log = scope.ServiceProvider.GetService>().CurrentValue; commonLinkUtility.GetLocationByRequest(out var product, out var module); if (product == null && CallContext.GetData("asc.web.product_id") != null) { product = webItemManager[(Guid)CallContext.GetData("asc.web.product_id")] as IProduct; } var logoText = TenantWhiteLabelSettings.DefaultLogoText; if ((tenantExtra.Enterprise || coreBaseSettings.CustomMode) && !MailWhiteLabelSettings.IsDefault(settingsManager, configuration)) { logoText = 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, commonLinkUtility.GetFullAbsolutePath(commonLinkUtility.GetUserProfile(aid)))); request.Arguments.Add(new TagValue(CommonTags.VirtualRootPath, 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, commonLinkUtility.GetFullAbsolutePath(product != null ? product.StartURL : "~"))); request.Arguments.Add(new TagValue(CommonTags.DateTime, tenantUtil.DateTimeNow())); request.Arguments.Add(new TagValue(CommonTags.RecipientID, Context.SYS_RECIPIENT_ID)); request.Arguments.Add(new TagValue(CommonTags.ProfileUrl, commonLinkUtility.GetFullAbsolutePath(commonLinkUtility.GetMyStaff()))); request.Arguments.Add(new TagValue(CommonTags.HelpLink, commonLinkUtility.GetHelpLink(settingsManager, additionalWhiteLabelSettingsHelper, false))); request.Arguments.Add(new TagValue(CommonTags.LetterLogoText, logoText)); request.Arguments.Add(new TagValue(CommonTags.MailWhiteLabelSettings, MailWhiteLabelSettings.Instance(settingsManager))); if (!request.Arguments.Any(x => CommonTags.SendFrom.Equals(x.Tag))) { request.Arguments.Add(new TagValue(CommonTags.SendFrom, tenant.Name)); } AddLetterLogo(request, tenantExtra, tenantLogoManager, coreBaseSettings, 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; } } public static class NotifyConfigurationExtension { public static IServiceCollection AddNotifyConfiguration(this IServiceCollection services) { return services .AddJabberStylerService() .AddTextileStylerService() .AddPushStylerService() .AddTenantManagerService() .AddAuthContextService() .AddUserManagerService() .AddDisplayUserSettingsService() .AddTenantExtraService() .AddWebItemManagerSecurity() .AddWebItemManager() .AddTenantLogoManagerService() .AddTenantUtilService() .AddCoreBaseSettingsService() .AddAdditionalWhiteLabelSettingsService() .AddCommonLinkUtilityService() .AddMailWhiteLabelSettingsService(); } } }