Blazor sanitize MarkupString - asp.net-core

I'm trying to sanitize content of MarkupString. Actually I created this (based from https://github.com/dotnet/aspnetcore/blob/574be0d22c1678ed5f6db990aec78b4db587b267/src/Components/Components/src/MarkupString.cs)
public struct MarkupStringSanitized
{
public MarkupStringSanitized(string value)
{
Value = value.Sanitize();
}
public string Value { get; }
public static explicit operator MarkupStringSanitized(string value) => new MarkupStringSanitized(value);
public override string ToString() => Value ?? string.Empty;
}
But render output isn't raw html. How should I implement MarkupStringSanitized to use
#((MarkupStringSanitized)"Sanitize this content")

Couple of suggestions (Not necessarily for OP, but for anyone else looking to solve the problem):
You didn't provide the code that does the actual sanitization, so I'm going to state the (hopefully) obvious best practice and if you're following it, great. Do not use Regular Expressions (Regex) to parse HTML
Also, the Sanitize() method should follow the pattern of immutability in this case
I would suggest the following library Gans.XSS.HtmlSanitizer which is an active library and updated regularly.
The problem
Razor View Engine can doesn't know how to render a MarkupStringSanitized. Just because you duck typed a sanitized version of the same struct doesn't mean it can render it. To get this to render, you'll need to cast it to something it does know, MarkupString
Here's what happens when I used your HtmlSanitizedMarkup directly with no modifications.
#((MarkupStringSanitized)Content)
Working Example #1
Here's an example using my Markdown -> Html playground (fully tested and working):
MarkupStringSanitized.cs
public struct MarkupStringSanitized
{
public MarkupStringSanitized(string value)
{
Value = Sanitize(value);
}
public string Value { get; }
public static explicit operator MarkupStringSanitized(string value) => new MarkupStringSanitized(value);
public static explicit operator MarkupString(MarkupStringSanitized value) => new MarkupString(value.Value);
public override string ToString() => Value ?? string.Empty;
private static string Sanitize(string value) {
var sanitizer = new HtmlSanitizer();
return sanitizer.Sanitize(value);
}
}
MarkupStringSanitizedComponent.razor
#if (Content == null)
{
<span>Loading...</span>
}
else
{
#((MarkupString)(MarkupStringSanitized)Content)
}
#code {
[Parameter] public string Content { get; set; }
}
That extra conversion though is ugly IMO. (maybe someone smarter than me can clean that up?)
Working example #2
Here I tried extending the MarkupString with an extension method. It looks a little better, but only a little.
MarkupStringExtensions.cs
public static class MarkupStringExtensions
{
public static MarkupString Sanitize(this MarkupString markupString)
{
return new MarkupString(SanitizeInput(markupString.Value));
}
private static string SanitizeInput(string value)
{
var sanitizer = new HtmlSanitizer();
return sanitizer.Sanitize(value);
}
}
MarkupStringSanitizedComponent.razor
#if (Content == null)
{
<span>Loading...</span>
}
else
{
#(((MarkupString)Content).Sanitize())
}
#code {
[Parameter] public string Content { get; set; }
}

Related

How can I validate different types within a collection using FluentValidation?

I have a class with a collection that needs validation. The generic on the collection takes an interface and different types can be added to the collection.
What is the cleanest path forward to creating a FluentValidation validator that supports polymorphism?
public interface IWizardStep {}
public class WizardOne : IWizardStep
{
public string Model { get; set; }
}
public class WizardTwo : IWizardStep
{
public string FirstName { get; set; }
}
public class Wizard
{
public Wizard()
{
var w1 = new WizardOne();
var w2 = new WizardTwo();
Steps = new List<IWizardStep>
{
w1,
w2
};
}
public IList<IWizardStep> Steps { get; set; }
}
public class WizardValidator : AbstractValidator<Wizard>
{
public WizardValidator()
{
RuleFor(x => x.Steps)
// Steps First where is WizardOne
// Model.NotEmpty()
// Steps First where is WizardTwo
// FirstName.NotEmpty()
}
FluentValidation doesn't support polymorphism for child collections like this out of the box, but you can add this behaviour by using a custom property validator, or by using OfType in your rule definitions.
I've written about both approaches before here:
Step 1: Create a validator for each implementor
Start by creating a validator for WizardOne and WizardTwo:
public class WizardOneValidator : AbstractValidator<WizardOne> {
public WizardOneValidator() {
RuleFor(x => x.Model).NotEmpty();
}
}
public class WizardTwoValidator : AbstractValidator<WizardTwo> {
public WizardTwoValidator() {
RuleFor(x => x.FirstName).NotEmpty();
}
}
Step 2: Create the parent validator
You have two options for defining the parent validator. The simplest approach is to use OfType, but this is less performant. The more complex option is to use a custom property validator.
Option 1: Using OfType
public WizardValidator : AbstractValidator<Wizard> {
public WizardValidator() {
RuleForEach(x => x.Steps.OfType<WizardOne>()).SetValidator(new WizardOneValidator());
RuleForEach(x => x.Steps.OfType<WizardTwo>()).SetValidator(new WizardTwoValidator());
}
}
This is the simplest approach, but calling OfType inside the call RuleFor will end up bypassing FluentValidation's expression cache, which is a potential performance hit. It also iterates the collection multiple. This may or may not be an issue for you - you'll need to decide if this has any real-world impact on your application.
Option 2: Using a custom PropertyValidator.
This uses a custom custom validator which can differentiate the underlying type at runtime:
public WizardValidator : AbstractValidator<Wizard> {
public WizardValidator() {
RuleForEach(x => x.Steps).SetValidator(new PolymorphicValidator<Wizard, IWizardStep>()
.Add<WizardOne>(new WizardOneValidator())
.Add<WizardTwo>(new WizardTwoValidator())
);
}
}
Syntactically, this isn't quite as nice, but doesn't bypass the expression cache and doesn't iterate the collection multiple times. This is the code for the PolymorphicValidator:
public class PolymorphicValidator<T, TInterface> : ChildValidatorAdaptor<T, TInterface> {
readonly Dictionary<Type, IValidator> _derivedValidators = new Dictionary<Type, IValidator>();
// Need the base constructor call, even though we're just passing null.
public PolymorphicValidator() : base((IValidator<TInterface>)null, typeof(IValidator<TInterface>)) {
}
public PolymorphicValidator<T, TInterface> Add<TDerived>(IValidator<TDerived> derivedValidator) where TDerived : TInterface {
_derivedValidators[typeof(TDerived)] = derivedValidator;
return this;
}
public override IValidator<TInterface> GetValidator(PropertyValidatorContext context) {
// bail out if the current item is null
if (context.PropertyValue == null) return null;
if (_derivedValidators.TryGetValue(context.PropertyValue.GetType(), out var derivedValidator)) {
return new ValidatorWrapper(derivedValidator);
}
return null;
}
private class ValidatorWrapper : AbstractValidator<TInterface> {
private IValidator _innerValidator;
public ValidatorWrapper(IValidator innerValidator) {
_innerValidator = innerValidator;
}
public override ValidationResult Validate(ValidationContext<TInterface> context) {
return _innerValidator.Validate(context);
}
public override Task<ValidationResult> ValidateAsync(ValidationContext<TInterface> context, CancellationToken cancellation = new CancellationToken()) {
return _innerValidator.ValidateAsync(context, cancellation);
}
public override IValidatorDescriptor CreateDescriptor() {
return _innerValidator.CreateDescriptor();
}
}
}
This will probably be implemented in the library as a first class feature at some point in the future - you can track its development here if you're interested.

How to see arguments when creating a new class?

When creating a new class or method I used to be able to see the parameters needed. But, now they don't come up anymore. How do I view parameters when creating a class?
Running the latest windows version.
public class Main {
public static void main(String args[]) {
Case theCase = new Case("Default", "Corsair", "500W");
}
}
public class Case {
private String model;
private String manufacturer;
private String powerSupply;
public Case(String model, String manufacturer, String powerSupply,) {
this.model = model;
this.manufacturer = manufacturer;
this.powerSupply = powerSupply;
}
public void pressPowerButton() {
System.out.println("Power button pressed");
}
public String getModel() {
return model;
}
public String getManufacturer() {
return manufacturer;
}
public String getPowerSupply() {
return powerSupply;
}
}
When making theCase I can't see what my parameters are and have to move to the "Case" class back and forth
You can explicitly call Parameter Info action which is usually mapped to Ctrl/(Cmd) - p.
Nevermind in order to see the parameters as you type you must type them while in the editor without moving your cursor.

How to add new language to ABP template?

I'm using free boilerplate (ASP.NET Core MVC & jQuery) from this site https://aspnetboilerplate.com/Templates
Is it possible to add new language support?
I already add localized .xml file, update 'abplanguages' table in database but it is not working. I'm changing language but text is still in english. The same situation with predefined languages already shipped with boilerplate like 'espanol-mexico' is not working but when I pick 'french' the page is translated.
This is weird because in documentation said it can be done.
https://aspnetboilerplate.com/Pages/Documents/Localization#extending-localization-sources
I wonder is it free template restriction?
inject IApplicationLanguageManager interface and use AddAsync() method to add a new language.
private readonly IApplicationLanguageManager _applicationLanguageManager;
public LanguageAppService(
IApplicationLanguageManager applicationLanguageManager,
IApplicationLanguageTextManager applicationLanguageTextManager,
IRepository<ApplicationLanguage> languageRepository)
{
_applicationLanguageManager = applicationLanguageManager;
_languageRepository = languageRepository;
_applicationLanguageTextManager = applicationLanguageTextManager;
}
protected virtual async Task CreateLanguageAsync(ApplicationLanguageEditDto input)
{
if (AbpSession.MultiTenancySide != MultiTenancySides.Host)
{
throw new UserFriendlyException(L("TenantsCannotCreateLanguage"));
}
var culture = CultureHelper.GetCultureInfoByChecking(input.Name);
await _applicationLanguageManager.AddAsync(
new ApplicationLanguage(
AbpSession.TenantId,
culture.Name,
culture.DisplayName,
input.Icon
)
{
IsDisabled = !input.IsEnabled
}
);
}
public static class CultureHelper
{
public static CultureInfo[] AllCultures = CultureInfo.GetCultures(CultureTypes.AllCultures);
public static bool IsRtl => CultureInfo.CurrentUICulture.TextInfo.IsRightToLeft;
public static bool UsingLunarCalendar = CultureInfo.CurrentUICulture.DateTimeFormat.Calendar.AlgorithmType == CalendarAlgorithmType.LunarCalendar;
public static CultureInfo GetCultureInfoByChecking(string name)
{
try
{
return CultureInfo.GetCultureInfo(name);
}
catch (CultureNotFoundException)
{
return CultureInfo.CurrentCulture;
}
}
}
public class ApplicationLanguageEditDto
{
public virtual int? Id { get; set; }
[Required]
[StringLength(ApplicationLanguage.MaxNameLength)]
public virtual string Name { get; set; }
[StringLength(ApplicationLanguage.MaxIconLength)]
public virtual string Icon { get; set; }
/// <summary>
/// Mapped from Language.IsDisabled with using manual mapping in CustomDtoMapper.cs
/// </summary>
public bool IsEnabled { get; set; }
}
I figure it out. In my case it was incorrect build action property. In VS right click on localization source file: *.xml file -> Advanced -> Build action: Embedded resource.

Can you access the metadata of other properties for ASP.NET Core 2.1 MVC client side validation?

I am looking at implementing some pretty simple client side validation by implementing the IClientModelValidator interface. Specifically I am creating a NotEqualTo (and later an EqualTo) validation attribute that will compare the value of one input to another.
To provide a nice UX I want to use the display name of both inputs in the error messages: "Password cannot be the same as Email" for example.
This is has obviously been done a million times and there are plenty of example around, but they are either for previous versions of MVC or are not using the display name of the other property.
Below is what I have so far. I have managed to grab the display name via the Display attribute in the server side IsValid(...) method, but I can't work out how to do similar for the client side AddValidation(...) method.
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class NotEqualToAttribute : ValidationAttribute, IClientModelValidator
{
private const string defaultErrorMessage = "{0} cannot be the same as {1}.";
public string OtherProperty { get; private set; }
public NotEqualToAttribute(string otherProperty) : base(defaultErrorMessage)
{
this.OtherProperty = otherProperty;
}
public override string FormatErrorMessage(string name)
{
string.Format(base.ErrorMessageString, name, this.OtherProperty);
}
public void AddValidation(ClientModelValidationContext context)
{
context.Attributes.Add("data-val", "true");
context.Attributes.Add("data-val-notequalto", this.FormatErrorMessage(context.ModelMetadata.GetDisplayName());
context.Attributes.Add("data-val-notequalto-otherproperty", this.otherProperty);
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
if (value == null)
return ValidationResult.Success;
PropertyInfo otherProperty = validationContext.ObjectInstance.GetType().GetProperty(this.OtherProperty);
object otherValue = otherProperty.GetValue(validationContext.ObjectInstance, null);
if (!value.Equals(otherValue))
return ValidationResult.Success;
DisplayAttribute display = otherProperty.GetCustomAttribute<DisplayAttribute>();
string otherName = display?.GetName() ?? this.OtherProperty;
return new ValidationResult(string.Format(defaultErrorMessage, validationContext.DisplayName, otherName));
}
}
Typically I solved this myself after taking a break, just going to leave this here in case it helps someone else (or there is a better solution):
public void AddValidation(ClientModelValidationContext context)
{
context.Attributes.Add("data-val", "true");
string otherName =
context.ModelMetadata.ContainerMetadata.Properties
.Single(p => p.PropertyName == this.OtherProperty)
.GetDisplayName();
context.Attributes.Add("data-val-notequalto",
string.Format(defaultErrorMessage, context.ModelMetadata.GetDisplayName(), otherName)
);
}
You can get to the meta data for the other properties via ClientModelValidationContext.ModelMetadata.ContainerMetadata.Properties

how do we return all attributes of a node with neo4jclient?

below code(search function) works fine.
public class BookItem
{
public string Title { get; set; }
public string OriginalTitle { get; set; }
}
public IEnumerable<dynamic> Search(string keyword)
{
/*MATCH (n:`Book`) RETURN n*/
var query = client
.Cypher
.Match("(n:Book)")
.Return(n => n.As<BookItem>());
return query.Results;
}
However, i don't want to declare a class like BookItem. I just want all results in a dynamic object. Is there a way to do that?
For example below code runs and returns empty object, it doesn't return any attributes..
public IEnumerable<dynamic> Search(string keyword)
{
/*MATCH (n:`Book`) RETURN n*/
var query = client
.Cypher
.Match("(n:Book)")
.Return(n => n.As<dynamic>());
return query.Results;
}
The basic gist is in the answer to this question: Casting nodes of an unknown type
What you end up returning is Node<string> and parsing using Json.net into a dynamic object, there is no direct way of just doing x.As<dynamic>() unfortunately.