Skip to content

Commit

Permalink
Closes #10.
Browse files Browse the repository at this point in the history
  • Loading branch information
JeremyLikness committed Sep 8, 2020
1 parent d5ea3cd commit f476b6a
Show file tree
Hide file tree
Showing 25 changed files with 442 additions and 23 deletions.
4 changes: 4 additions & 0 deletions Releases.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ the [`RulesEngine`](./docs/api/ExpressionPowerTools.Serialization.Rules.RulesEng
- Added [`TypeBase`](./docs/api/ExpressionPowerTools.Serialization.Serializers.TypeBase.cs.md) for easy key calculation for types.
- Added [`MemberSelector`](./docs/api/ExpressionPowerTools.Serialization.Rules.MemberSelector`1.cs.md) to provide
ways to specify members when configuring rules using [`SelectorExtensions`](./docs/api/ExpressionPowerTools.Serialization.Extensions.SelectorExtensions.cs.md)
- Added lazy service requests to [`ServiceHost`](./docs/api/ExpressionPowerTools.Core.Dependencies.ServiceHost.cs.md)
- Modified the expressions with methods and members (`BinaryExpression`, `NewExpression`, `MethodCallExpression` and
`MemberAccessExpression`) to make authorization checks
- Added the [`ConfigureRules`](./docs/api/ExpressionPowerTools.Serialization.Serializer.ConfigureRules.m.md) method

### 0.8.5-alpha

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,17 @@ namespace ExpressionPowerTools.Core.Comparisons
/// </summary>
public static class ExpressionEquivalency
{
/// <summary>
/// A lazy proxy to the rules.
/// </summary>
private static readonly Lazy<IExpressionComparisonRuleProvider> Provider =
ServiceHost.GetLazyService<IExpressionComparisonRuleProvider>();

/// <summary>
/// Gets the configured rule set.
/// </summary>
private static IExpressionComparisonRuleProvider Rules =>
ServiceHost.GetService<IExpressionComparisonRuleProvider>();
Provider.Value;

/// <summary>
/// Determine if a <see cref="Type"/> is equivalent to another type.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,17 @@ namespace ExpressionPowerTools.Core.Comparisons
/// </summary>
public static class ExpressionSimilarity
{
/// <summary>
/// A lazy proxy to the rules.
/// </summary>
private static readonly Lazy<IExpressionComparisonRuleProvider> Provider =
ServiceHost.GetLazyService<IExpressionComparisonRuleProvider>();

/// <summary>
/// Gets the configured rule set.
/// </summary>
private static IExpressionComparisonRuleProvider Rules =>
ServiceHost.GetService<IExpressionComparisonRuleProvider>();
Provider.Value;

/// <summary>
/// Entry for similarity comparisons. Will cast to
Expand Down
32 changes: 32 additions & 0 deletions src/ExpressionPowerTools.Core/Dependencies/ServiceHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Licensed under the MIT License. See LICENSE in the repository root for license information.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using ExpressionPowerTools.Core.Comparisons;
Expand Down Expand Up @@ -62,6 +63,12 @@ public static class ServiceHost
/// </summary>
private static readonly object MutexLock = new object();

/// <summary>
/// The satellite registrations.
/// </summary>
private static readonly Stack<IDependentServiceRegistration> Satellites =
new Stack<IDependentServiceRegistration>();

/// <summary>
/// A value indicating whether the container has already been configured.
/// </summary>
Expand Down Expand Up @@ -102,6 +109,8 @@ public static void Reset()
RegisterSatellites(register);
});

AfterRegistered();

Monitor.Exit(MutexLock);
}

Expand All @@ -114,6 +123,15 @@ public static void Reset()
public static T GetService<T>(params object[] parameters) =>
Services.GetService<T>(parameters);

/// <summary>
/// Gets a lazy loaded service.
/// </summary>
/// <typeparam name="T">The <see cref="Type"/> of the service.</typeparam>
/// <param name="parameters">The parameters.</param>
/// <returns>The lazy intialization for the service.</returns>
public static Lazy<T> GetLazyService<T>(params object[] parameters) =>
new Lazy<T>(() => GetService<T>(parameters), LazyThreadSafetyMode.PublicationOnly);

/// <summary>
/// Initialize the container. Can only be done once unless
/// <see cref="Reset"/> is called.
Expand Down Expand Up @@ -144,13 +162,26 @@ public static void Initialize(Action<IServiceRegistration> registration)
registration(register);
});
configured = true;
AfterRegistered();
}
finally
{
Monitor.Exit(MutexLock);
}
}

/// <summary>
/// Notifies satellite assemblies registation is done.
/// </summary>
private static void AfterRegistered()
{
while (Satellites.Count > 0)
{
var satellite = Satellites.Pop();
satellite.AfterRegistered();
}
}

/// <summary>
/// Registers the default instances.
/// </summary>
Expand Down Expand Up @@ -181,6 +212,7 @@ private static void RegisterSatellites(IServiceRegistration register)
{
var satelliteRegistration = Activator.CreateInstance(dependent) as IDependentServiceRegistration;
satelliteRegistration.RegisterDefaultServices(register);
Satellites.Push(satelliteRegistration);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,10 @@ public interface IDependentServiceRegistration
/// </summary>
/// <param name="registration">The <see cref="IServiceRegistration"/>.</param>
void RegisterDefaultServices(IServiceRegistration registration);

/// <summary>
/// Called after registration is complete.
/// </summary>
void AfterRegistered();
}
}
28 changes: 27 additions & 1 deletion src/ExpressionPowerTools.Serialization/Registration.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
// Copyright (c) Jeremy Likness. All rights reserved.
// Licensed under the MIT License. See LICENSE in the repository root for license information.

using System;
using System.Linq;
using ExpressionPowerTools.Core.Dependencies;
using ExpressionPowerTools.Core.Signatures;
using ExpressionPowerTools.Serialization.Configuration;
using ExpressionPowerTools.Serialization.Rules;
Expand All @@ -14,6 +17,18 @@ namespace ExpressionPowerTools.Serialization
/// </summary>
public class Registration : IDependentServiceRegistration
{
/// <summary>
/// Registers the default rules.
/// </summary>
/// <param name="rules">The <see cref="IRulesConfiguration"/>.</param>
public static void RegisterDefaultRules(IRulesConfiguration rules)
{
rules.RuleForType(typeof(Math))
.RuleForType(typeof(Enumerable))
.RuleForType(typeof(Queryable))
.RuleForType<string>();
}

/// <summary>
/// Registers the services used by serialization.
/// </summary>
Expand All @@ -24,7 +39,18 @@ public void RegisterDefaultServices(IServiceRegistration registration)
new ReflectionHelper());
registration.Register<IConfigurationBuilder, ConfigurationBuilder>();
registration.RegisterSingleton<IDefaultConfiguration>(new DefaultConfiguration());
registration.RegisterSingleton<IRulesEngine>(new RulesEngine());
var rules = new RulesEngine();
registration.RegisterSingleton<IRulesEngine>(rules);
registration.RegisterSingleton<IRulesConfiguration>(rules);
}

/// <summary>
/// Adds default "safe" rules for serialization.
/// </summary>
public void AfterRegistered()
{
var rules = ServiceHost.GetService<IRulesConfiguration>();
RegisterDefaultRules(rules);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ public IRulesConfiguration RuleForConstructor(Action<MemberSelector<ConstructorI
var ctorSelector = new MemberSelector<ConstructorInfo>();
selector(ctorSelector);
memberInfo = ctorSelector.Member;
compiled = false;
return this;
}

Expand All @@ -64,6 +65,7 @@ public IRulesConfiguration RuleForField(Action<MemberSelector<FieldInfo>> select
var fieldSelector = new MemberSelector<FieldInfo>();
selector(fieldSelector);
memberInfo = fieldSelector.Member;
compiled = false;
return this;
}

Expand All @@ -78,6 +80,7 @@ public IRulesConfiguration RuleForMethod(Action<MemberSelector<MethodInfo>> sele
var methodSelector = new MemberSelector<MethodInfo>();
selector(methodSelector);
memberInfo = methodSelector.Member;
compiled = false;
return this;
}

Expand All @@ -92,6 +95,7 @@ public IRulesConfiguration RuleForProperty(Action<MemberSelector<PropertyInfo>>
var propSelector = new MemberSelector<PropertyInfo>();
selector(propSelector);
memberInfo = propSelector.Member;
compiled = false;
return this;
}

Expand All @@ -104,6 +108,7 @@ public IRulesConfiguration RuleForType(Type type)
{
CheckMemberInfo(shouldExist: false);
memberInfo = new[] { type };
compiled = false;
return this;
}

Expand Down
60 changes: 50 additions & 10 deletions src/ExpressionPowerTools.Serialization/Rules/RulesEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading;
using ExpressionPowerTools.Core.Dependencies;
using ExpressionPowerTools.Serialization.Serializers;
using ExpressionPowerTools.Serialization.Signatures;
Expand Down Expand Up @@ -32,10 +33,10 @@ namespace ExpressionPowerTools.Serialization.Rules
public partial class RulesEngine : IRulesEngine
{
/// <summary>
/// Instance of the <see cref="ReflectionHelper"/>.
/// Provider for <see cref="IReflectionHelper"/>.
/// </summary>
private readonly Lazy<IReflectionHelper> reflectionHelper =
new Lazy<IReflectionHelper>(() => ServiceHost.GetService<IReflectionHelper>());
private readonly Lazy<IReflectionHelper> reflectionProvider =
ServiceHost.GetLazyService<IReflectionHelper>();

/// <summary>
/// The collection of rules.
Expand Down Expand Up @@ -69,6 +70,11 @@ public partial class RulesEngine : IRulesEngine
/// </summary>
private bool compiled;

/// <summary>
/// Gets an instance of the <see cref="ReflectionHelper"/>.
/// </summary>
private IReflectionHelper ReflectionHelper => reflectionProvider.Value;

/// <summary>
/// Adds a rule to the engine.
/// </summary>
Expand Down Expand Up @@ -123,7 +129,7 @@ public bool MemberIsAllowed(MemberInfo member)
}

// easiest check
var memberKey = reflectionHelper.Value.TranslateMemberInfo(member);
var memberKey = ReflectionHelper.TranslateMemberInfo(member);
var key = memberKey.CalculateKey();
if (permissions.ContainsKey(key))
{
Expand All @@ -135,10 +141,18 @@ public bool MemberIsAllowed(MemberInfo member)
typeDef : member.DeclaringType;
var typeKey = new TypeBase(type).CalculateKey();

// is the type allowed or denied? This will inherit.
if (permissions.ContainsKey(typeKey))
{
var permission = permissions[typeKey];
permissions.Add(key, permission);
return permission;
}

if (type.IsGenericType && !type.IsGenericTypeDefinition)
{
var generic = type.GetGenericTypeDefinition();
memberKey = reflectionHelper.Value.TranslateMemberInfo(generic);
memberKey = ReflectionHelper.TranslateMemberInfo(generic);
var genericKey = memberKey.CalculateKey();
if (permissions.ContainsKey(genericKey))
{
Expand All @@ -150,10 +164,10 @@ public bool MemberIsAllowed(MemberInfo member)
}
}

var genericVersion = reflectionHelper.Value.FindGenericVersion(member, generic);
var genericVersion = ReflectionHelper.FindGenericVersion(member, generic);
if (genericVersion != null)
{
var genericVersionKey = reflectionHelper.Value.TranslateMemberInfo(genericVersion)
var genericVersionKey = ReflectionHelper.TranslateMemberInfo(genericVersion)
.CalculateKey();
if (permissions.ContainsKey(genericVersionKey))
{
Expand Down Expand Up @@ -201,6 +215,11 @@ public void Compile()
r.MemberType == MemberTypes.TypeInfo ||
r.MemberType == MemberTypes.NestedType))
{
if (compiledPermissions.ContainsKey(rule.TargetKey))
{
continue;
}

var permission = rule.Allow;
compiledPermissions.Add(rule.TargetKey, permission);

Expand All @@ -211,15 +230,23 @@ public void Compile()
.Union(type.GetProperties(allpublic))
.Union(type.GetFields(allpublic))
.Union(type.GetConstructors(allpublic))
.Select(m => reflectionHelper.Value.TranslateMemberInfo(m).CalculateKey());
.Select(m => ReflectionHelper.TranslateMemberInfo(m).CalculateKey());
foreach (var child in children)
{
compiledPermissions.Add(child, permission);
if (!compiledPermissions.ContainsKey(child))
{
compiledPermissions.Add(child, permission);
}
else
{
compiledPermissions[child] = permission;
}
}
}

// overrides
foreach (var rule in rules.Where(r => r.MemberType != MemberTypes.All))
foreach (var rule in rules.Where(r => r.MemberType != MemberTypes.TypeInfo &&
r.MemberType != MemberTypes.NestedType))
{
if (compiledPermissions.ContainsKey(rule.TargetKey))
{
Expand All @@ -242,5 +269,18 @@ public void Compile()
compiled = true;
}
}

/// <summary>
/// Clears the ruleset.
/// </summary>
public void Reset()
{
Monitor.Enter(objLock);
rules.Clear();
typeHierarchy.Clear();
permissions.Clear();
compiled = false;
Monitor.Exit(objLock);
}
}
}
Loading

0 comments on commit f476b6a

Please sign in to comment.