private async ValueTask BuildViewModel(MarkdownBodyPartViewModel model, MarkdownBodyPart markdownBodyPart, BuildPartDisplayContext context)
        {
            model.Markdown         = markdownBodyPart.Markdown;
            model.MarkdownBodyPart = markdownBodyPart;
            model.ContentItem      = markdownBodyPart.ContentItem;

            // The default Markdown option is to entity escape html
            // so filters must be run after the markdown has been processed.
            model.Html = _markdownService.ToHtml(model.Markdown ?? "");

            var settings = context.TypePartDefinition.GetSettings <MarkdownBodyPartSettings>();

            // The liquid rendering is for backwards compatibility and can be removed in a future version.
            if (!settings.SanitizeHtml)
            {
                model.Html = await _liquidTemplateManager.RenderStringAsync(model.Html, _htmlEncoder, model,
                                                                            new Dictionary <string, FluidValue>() { ["ContentItem"] = new ObjectValue(model.ContentItem) });
            }

            model.Html = await _shortcodeService.ProcessAsync(model.Html,
                                                              new Context
            {
                ["ContentItem"]        = markdownBodyPart.ContentItem,
                ["TypePartDefinition"] = context.TypePartDefinition
            });

            if (settings.SanitizeHtml)
            {
                model.Html = _htmlSanitizerService.Sanitize(model.Html ?? "");
            }
        }
        public override IDisplayResult Display(MarkdownField field, BuildFieldDisplayContext context)
        {
            return(Initialize <MarkdownFieldViewModel>(GetDisplayShapeType(context), async model =>
            {
                var settings = context.PartFieldDefinition.GetSettings <MarkdownFieldSettings>();
                model.Markdown = field.Markdown;
                model.Field = field;
                model.Part = context.ContentPart;
                model.PartFieldDefinition = context.PartFieldDefinition;

                // The default Markdown option is to entity escape html
                // so filters must be run after the markdown has been processed.
                model.Html = _markdownService.ToHtml(model.Markdown ?? "");

                // The liquid rendering is for backwards compatability and can be removed in a future version.
                if (!settings.SanitizeHtml)
                {
                    model.Markdown = await _liquidTemplateManager.RenderAsync(model.Html, _htmlEncoder, model,
                                                                              scope => scope.SetValue("ContentItem", field.ContentItem));
                }

                model.Html = await _shortCodeService.ProcessAsync(model.Html ?? "");

                if (settings.SanitizeHtml)
                {
                    model.Html = _htmlSanitizerService.Sanitize(model.Html ?? "");
                }
            })
                   .Location("Detail", "Content")
                   .Location("Summary", "Content"));
        }
        public ValueTask <FluidValue> ProcessAsync(FluidValue input, FilterArguments arguments, LiquidTemplateContext ctx)
        {
            var html = input.ToStringValue();

            html = _htmlSanitizerService.Sanitize(html);

            return(new ValueTask <FluidValue>(new StringValue(html)));
        }
        public override async Task <IDisplayResult> UpdateAsync(LinkField field, IUpdateModel updater, UpdateFieldEditorContext context)
        {
            var modelUpdated = await updater.TryUpdateModelAsync(field, Prefix, f => f.Url, f => f.Text);

            if (modelUpdated)
            {
                var settings = context.PartFieldDefinition.GetSettings <LinkFieldSettings>();

                var urlToValidate = field.Url;
                if (!String.IsNullOrEmpty(urlToValidate))
                {
                    var indexAnchor = urlToValidate.IndexOf('#');
                    if (indexAnchor > -1)
                    {
                        urlToValidate = urlToValidate.Substring(0, indexAnchor);
                    }

                    if (urlToValidate.StartsWith("~/", StringComparison.Ordinal))
                    {
                        var urlHelper = _urlHelperFactory.GetUrlHelper(_actionContextAccessor.ActionContext);
                        urlToValidate = urlHelper.Content(urlToValidate);
                    }

                    urlToValidate = urlToValidate.ToUriComponents();
                }

                // Validate Url
                if (settings.Required && String.IsNullOrWhiteSpace(field.Url))
                {
                    updater.ModelState.AddModelError(Prefix, nameof(field.Url), S["The url is required for {0}.", context.PartFieldDefinition.DisplayName()]);
                }
                else if (!String.IsNullOrWhiteSpace(field.Url) && !Uri.IsWellFormedUriString(urlToValidate, UriKind.RelativeOrAbsolute))
                {
                    updater.ModelState.AddModelError(Prefix, nameof(field.Url), S["{0} is an invalid url.", field.Url]);
                }
                else
                {
                    var link = $"<a href=\"{_htmlencoder.Encode(urlToValidate)}\"></a>";

                    if (!String.Equals(link, _htmlSanitizerService.Sanitize(link), StringComparison.OrdinalIgnoreCase))
                    {
                        updater.ModelState.AddModelError(Prefix, nameof(field.Url), S["{0} is an invalid url.", field.Url]);
                    }
                }

                // Validate Text
                if (settings.LinkTextMode == LinkTextMode.Required && String.IsNullOrWhiteSpace(field.Text))
                {
                    updater.ModelState.AddModelError(Prefix, nameof(field.Text), S["The link text is required for {0}.", context.PartFieldDefinition.DisplayName()]);
                }
                else if (settings.LinkTextMode == LinkTextMode.Static && String.IsNullOrWhiteSpace(settings.DefaultText))
                {
                    updater.ModelState.AddModelError(Prefix, nameof(field.Text), S["The text default value is required for {0}.", context.PartFieldDefinition.DisplayName()]);
                }
            }

            return(Edit(field, context));
        }
Example #5
0
        public override Task GetContentItemAspectAsync(ContentItemAspectContext context, MarkdownBodyPart part)
        {
            return(context.ForAsync <BodyAspect>(async bodyAspect =>
            {
                if (bodyAspect != null && part.ContentItem.Id == _contentItemId)
                {
                    bodyAspect.Body = _bodyAspect;

                    return;
                }

                try
                {
                    var contentTypeDefinition = _contentDefinitionManager.GetTypeDefinition(part.ContentItem.ContentType);
                    var contentTypePartDefinition = contentTypeDefinition.Parts.FirstOrDefault(x => String.Equals(x.PartDefinition.Name, "MarkdownBodyPart"));
                    var settings = contentTypePartDefinition.GetSettings <MarkdownBodyPartSettings>();

                    // The default Markdown option is to entity escape html
                    // so filters must be run after the markdown has been processed.
                    var html = _markdownService.ToHtml(part.Markdown);

                    // The liquid rendering is for backwards compatability and can be removed in a future version.
                    if (!settings.SanitizeHtml)
                    {
                        var model = new MarkdownBodyPartViewModel()
                        {
                            Markdown = part.Markdown,
                            Html = html,
                            MarkdownBodyPart = part,
                            ContentItem = part.ContentItem
                        };

                        html = await _liquidTemplateManager.RenderAsync(html, _htmlEncoder, model,
                                                                        scope => scope.SetValue("ContentItem", model.ContentItem));
                    }

                    html = await _shortcodeService.ProcessAsync(html,
                                                                new Context
                    {
                        ["ContentItem"] = part.ContentItem,
                        ["TypePartDefinition"] = contentTypePartDefinition
                    });

                    if (settings.SanitizeHtml)
                    {
                        html = _htmlSanitizerService.Sanitize(html);
                    }

                    bodyAspect.Body = _bodyAspect = new HtmlString(html);
                    _contentItemId = part.ContentItem.Id;
                }
                catch
                {
                    bodyAspect.Body = HtmlString.Empty;
                    _contentItemId = default;
                }
            }));
        }
        public override IDisplayResult Display(HtmlMenuItemPart part, BuildPartDisplayContext context)
        {
            var settings = context.TypePartDefinition.GetSettings <HtmlMenuItemPartSettings>();

            if (settings.SanitizeHtml)
            {
                part.Html = _htmlSanitizerService.Sanitize(part.Html);
            }

            return(Combine(
                       Dynamic("HtmlMenuItemPart_Admin", shape =>
            {
                shape.MenuItemPart = part;
            })
                       .Location("Admin", "Content:10"),
                       Dynamic("HtmlMenuItemPart_Thumbnail", shape =>
            {
                shape.MenuItemPart = part;
            })
                       .Location("Thumbnail", "Content:10")
                       ));
        }
Example #7
0
        public override async Task <IDisplayResult> UpdateAsync(OrchardCore.ContentFields.Fields.HtmlField field, IUpdateModel updater, UpdateFieldEditorContext context)
        {
            // If it's an attached media field editor the files are automatically handled by _attachedMediaFieldFileService
            if (string.Equals(context.PartFieldDefinition.Editor(), "FroalaEditor", StringComparison.OrdinalIgnoreCase))
            {
                var viewModel = new EditHtmlFieldViewModel();

                var settings = context.PartFieldDefinition.GetSettings <HtmlFieldSettings>();

                // Deserializing an empty string doesn't return an array
                var items = string.IsNullOrWhiteSpace(viewModel.Paths)
                    ? new List <EditMediaFieldItemInfo>()
                    : JsonConvert.DeserializeObject <EditMediaFieldItemInfo[]>(viewModel.Paths).ToList();
                if (items.Any())
                {
                    try
                    {
                        await _attachedMediaToContentItemService.HandleFilesOnContentPartUpdateAsync(items,
                                                                                                     context.ContentPart.ContentItem);

                        //replace body temp file paths with new folder paths
                        //because froala encodes url paths to avoid xss must decode first before finding and replacing paths
                        var decodedHtml = HttpUtility.UrlDecode(viewModel.Html);
                        foreach (var mediaFieldItemInfo in items)
                        {
                            if (!String.IsNullOrEmpty(mediaFieldItemInfo.NewPath))
                            {
                                // vm.Body=  vm.Body.Replace(mediaFieldItemInfo.Path, mediaFieldItemInfo.NewPath);
                                decodedHtml = decodedHtml?.Replace(mediaFieldItemInfo.Path,
                                                                   mediaFieldItemInfo.NewPath);
                            }
                        }

                        //set back html to viewmodel
                        viewModel.Html = decodedHtml;
                    }
                    catch (Exception)
                    {
                        updater.ModelState.AddModelError(Prefix,
                                                         S["{0}: There was an error handling the files.",
                                                           context.TypePartDefinition.DisplayName()]);
                    }

                    field.Html = settings.SanitizeHtml
                        ? _htmlSanitizerService.Sanitize(viewModel.Html)
                        : viewModel.Html;
                }
            }

            return(await EditAsync(field, context));
        }
Example #8
0
        public override async Task <IDisplayResult> UpdateAsync(LinkMenuItemPart part, IUpdateModel updater)
        {
            var model = new LinkMenuItemPartEditViewModel();

            if (await updater.TryUpdateModelAsync(model, Prefix))
            {
                part.Url = model.Url;
                part.ContentItem.DisplayText = model.Name;

                // This code can be removed in a later release.
#pragma warning disable 0618
                part.Name = model.Name;
#pragma warning restore 0618

                var urlToValidate = part.Url;

                if (!String.IsNullOrEmpty(urlToValidate))
                {
                    urlToValidate = urlToValidate.Split('#', 2)[0];

                    if (urlToValidate.StartsWith("~/", StringComparison.Ordinal))
                    {
                        var urlHelper = _urlHelperFactory.GetUrlHelper(_actionContextAccessor.ActionContext);
                        urlToValidate = urlHelper.Content(urlToValidate);
                    }

                    urlToValidate = urlToValidate.ToUriComponents();

                    if (!Uri.IsWellFormedUriString(urlToValidate, UriKind.RelativeOrAbsolute))
                    {
                        updater.ModelState.AddModelError(nameof(part.Url), S["{0} is an invalid url.", part.Url]);
                    }
                    else
                    {
                        var link = $"<a href=\"{_htmlencoder.Encode(urlToValidate)}\"></a>";

                        if (!String.Equals(link, _htmlSanitizerService.Sanitize(link), StringComparison.OrdinalIgnoreCase))
                        {
                            updater.ModelState.AddModelError(nameof(part.Url), S["{0} is an invalid url.", part.Url]);
                        }
                    }
                }
            }

            return(Edit(part));
        }
Example #9
0
        private int SubstituteTag(string text, StringBuilderPool sb, int start, int modifierIndex, int end)
        {
            var url = text.Substring(start + 7, end - start - 7);

            // substitute [thetag] with <img>
            sb.Builder.Remove(start + modifierIndex, end - start + 8);

            var publicUrl = _mediaFileStore.MapPathToPublicUrl(url);

            var tag = "<img src=\"" + publicUrl + "\">";

            tag = _htmlSanitizerService.Sanitize(tag);

            sb.Builder.Insert(start + modifierIndex, tag);

            // Return the value the stringbuilder start index has been modified for recursion.
            return(publicUrl.Length - url.Length - 3);
        }
Example #10
0
        public override async Task <IDisplayResult> UpdateAsync(HtmlField field, IUpdateModel updater, UpdateFieldEditorContext context)
        {
            var viewModel = new EditHtmlFieldViewModel();

            var settings = context.PartFieldDefinition.GetSettings <HtmlFieldSettings>();

            if (await updater.TryUpdateModelAsync(viewModel, Prefix, f => f.Html))
            {
                if (!string.IsNullOrEmpty(viewModel.Html) && !_liquidTemplateManager.Validate(viewModel.Html, out var errors))
                {
                    var fieldName = context.PartFieldDefinition.DisplayName();
                    context.Updater.ModelState.AddModelError(Prefix, nameof(viewModel.Html), S["{0} doesn't contain a valid Liquid expression. Details: {1}", fieldName, string.Join(" ", errors)]);
                }
                else
                {
                    field.Html = settings.SanitizeHtml ? _htmlSanitizerService.Sanitize(viewModel.Html) : viewModel.Html;
                }
            }

            return(Edit(field, context));
        }
Example #11
0
        public override async Task <IDisplayResult> UpdateAsync(HtmlBodyPart model, IUpdateModel updater, UpdatePartEditorContext context)
        {
            var viewModel = new HtmlBodyPartViewModel();

            var settings = context.TypePartDefinition.GetSettings <HtmlBodyPartSettings>();

            if (await updater.TryUpdateModelAsync(viewModel, Prefix, t => t.Html))
            {
                if (!string.IsNullOrEmpty(viewModel.Html) && !_liquidTemplateManager.Validate(viewModel.Html, out var errors))
                {
                    var partName = context.TypePartDefinition.DisplayName();
                    updater.ModelState.AddModelError(Prefix, nameof(viewModel.Html), S["{0} doesn't contain a valid Liquid expression. Details: {1}", partName, string.Join(" ", errors)]);
                }
                else
                {
                    model.Html = settings.SanitizeHtml ? _htmlSanitizerService.Sanitize(viewModel.Html) : viewModel.Html;
                }
            }

            return(Edit(model, context));
        }
Example #12
0
        protected override IDisplayResult?BuildDisplay(MarkdownBodyPart contentPart, BuildPartDisplayContext context)
        {
            return(Shape(
                       nameof(MarkdownBodyPart),
                       async model =>
            {
                var shape = await model.New.MarkdownBodyPart();
                var markdown = contentPart.Markdown ?? "";
                var html = _markdownService.ToHtml(markdown);
                var settings = context.TypePartDefinition.GetSettings <MarkdownBodyPartSettings>();

                if (settings.SanitizeHtml)
                {
                    html = _htmlSanitizerService.Sanitize(html);
                }

                shape.Markdown = markdown;
                shape.Html = html;
                shape.ContentItem = contentPart.ContentItem;
                shape.MarkdownBodyPart = contentPart;
                return shape;
            })
                   .DefaultLocation("5"));
        }
Example #13
0
        private async ValueTask BuildViewModel(MarkdownBodyPartViewModel model, MarkdownBodyPart markdownBodyPart, MarkdownBodyPartSettings settings)
        {
            model.Markdown         = markdownBodyPart.Markdown;
            model.MarkdownBodyPart = markdownBodyPart;
            model.ContentItem      = markdownBodyPart.ContentItem;

            // The default Markdown option is to entity escape html
            // so filters must be run after the markdown has been processed.
            model.Html = _markdownService.ToHtml(model.Markdown ?? "");

            // The liquid rendering is for backwards compatability and can be removed in a future version.
            if (!settings.SanitizeHtml)
            {
                model.Html = await _liquidTemplateManager.RenderAsync(model.Html, _htmlEncoder, model,
                                                                      scope => scope.SetValue("ContentItem", model.ContentItem));
            }

            model.Html = await _shortCodeService.ProcessAsync(model.Html ?? "");

            if (settings.SanitizeHtml)
            {
                model.Html = _htmlSanitizerService.Sanitize(model.Html ?? "");
            }
        }
        public ValueTask <string> EvaluateAsync(string identifier, Arguments arguments, string content, Context context)
        {
            if (!Shortcodes.Contains(identifier))
            {
                return(Null);
            }

            // Handle self closing shortcodes.
            if (String.IsNullOrEmpty(content))
            {
                content = arguments.NamedOrDefault("src");
                if (String.IsNullOrEmpty(content))
                {
                    // Do not handle the deprecated media shortcode in this edge case.
                    return(ImageShortcode);
                }
            }

            if (!content.StartsWith("//", StringComparison.Ordinal) && !content.StartsWith("http", StringComparison.OrdinalIgnoreCase))
            {
                // Serve static files from virtual path.
                if (content.StartsWith("~/", StringComparison.Ordinal))
                {
                    content = _httpContextAccessor.HttpContext.Request.PathBase.Add(content.Substring(1)).Value;
                    if (!String.IsNullOrEmpty(_options.CdnBaseUrl))
                    {
                        content = _options.CdnBaseUrl + content;
                    }
                }
                else
                {
                    content = _mediaFileStore.MapPathToPublicUrl(content);
                }
            }
            var className = string.Empty;
            var altText   = string.Empty;

            if (arguments.Any())
            {
                var queryStringParams = new Dictionary <string, string>();

                var width   = arguments.Named("width");
                var height  = arguments.Named("height");
                var mode    = arguments.Named("mode");
                var quality = arguments.Named("quality");
                var format  = arguments.Named("format");
                className = arguments.Named("class");
                altText   = arguments.Named("alt");

                if (width != null)
                {
                    queryStringParams.Add("width", width);
                }

                if (height != null)
                {
                    queryStringParams.Add("height", height);
                }

                if (mode != null)
                {
                    queryStringParams.Add("rmode", mode);
                }

                if (quality != null)
                {
                    queryStringParams.Add("quality", quality);
                }

                if (format != null)
                {
                    queryStringParams.Add("format", format);
                }

                if (className != null)
                {
                    className = "class=\"" + className + "\" ";
                }

                if (altText != null)
                {
                    altText = "alt=\"" + altText + "\" ";
                }

                content = QueryHelpers.AddQueryString(content, queryStringParams);
            }

            content = "<img " + altText + className + "src=\"" + content + "\">";
            content = _htmlSanitizerService.Sanitize(content);

            return(new ValueTask <string>(content));
        }
Example #15
0
        public async Task <IActionResult> CreatePost(ShortcodeTemplateViewModel model, string submit)
        {
            if (!await _authorizationService.AuthorizeAsync(User, Permissions.ManageShortcodeTemplates))
            {
                return(Forbid());
            }

            if (ModelState.IsValid)
            {
                if (String.IsNullOrWhiteSpace(model.Name))
                {
                    ModelState.AddModelError(nameof(ShortcodeTemplateViewModel.Name), S["The name is mandatory."]);
                }
                else if (!IsValidShortcodeName(model.Name))
                {
                    ModelState.AddModelError(nameof(ShortcodeTemplateViewModel.Name), S["The name contains invalid characters."]);
                }
                else
                {
                    var shortcodeTemplatesDocument = await _shortcodeTemplatesManager.GetShortcodeTemplatesDocumentAsync();

                    if (shortcodeTemplatesDocument.ShortcodeTemplates.ContainsKey(model.Name))
                    {
                        ModelState.AddModelError(nameof(ShortcodeTemplateViewModel.Name), S["A template with the same name already exists."]);
                    }
                }

                if (String.IsNullOrEmpty(model.Content))
                {
                    ModelState.AddModelError(nameof(ShortcodeTemplateViewModel.Content), S["The template content is mandatory."]);
                }
                else if (!_liquidTemplateManager.Validate(model.Content, out var errors))
                {
                    ModelState.AddModelError(nameof(ShortcodeTemplateViewModel.Content), S["The template doesn't contain a valid Liquid expression. Details: {0}", String.Join(" ", errors)]);
                }
            }

            if (ModelState.IsValid)
            {
                var template = new ShortcodeTemplate
                {
                    Content      = model.Content,
                    Hint         = model.Hint,
                    Usage        = _htmlSanitizerService.Sanitize(model.Usage),
                    DefaultValue = model.DefaultValue,
                    Categories   = JsonConvert.DeserializeObject <string[]>(model.SelectedCategories)
                };

                await _shortcodeTemplatesManager.UpdateShortcodeTemplateAsync(model.Name, template);

                if (submit == "SaveAndContinue")
                {
                    return(RedirectToAction(nameof(Edit), new { name = model.Name }));
                }
                else
                {
                    return(RedirectToAction(nameof(Index)));
                }
            }

            // If we got this far, something failed, redisplay form
            return(View(model));
        }