blob: 0d5bb338231ff7ce06cb38b678fd9bc14a062783 [file] [log] [blame]
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Text.RegularExpressions;
using Casbin.Effect;
using Casbin.Model;
using Casbin.Util;
namespace Casbin
{
// TODO: The .NET Standard 2.0 TFM is not support private init.
[SuppressMessage("ReSharper", "PropertyCanBeMadeInitOnly.Local")]
public class EnforceView
{
public string RequestType { get; set; }
public IReadOnlyAssertion RequestAssertion { get; private set; }
public IReadOnlyList<string> RequestTokens { get; private set; }
public string PolicyType { get; set; }
public PolicyAssertion PolicyAssertion { get; private set; }
public IReadOnlyList<string> PolicyTokens { get; private set; }
public bool SupportGeneric { get; private set; }
public bool HasEffect { get; private set; }
public int EffectIndex { get; private set; }
public bool HasPriority { get; private set; }
public int PriorityIndex { get; private set; }
public string Effect { get; private set; }
public EffectExpressionType EffectExpressionType { get; private set; }
public string Matcher { get; private set; }
public string TransformedMatcher { get; private set; }
public bool HasRequestParameter { get; private set; }
public bool HasPolicyParameter { get; private set; }
public bool HasEval { get; private set; }
public IDictionary<string, int> EvalRules { get; private set; }
public static EnforceView Create(
IModel model,
string requestType = PermConstants.DefaultRequestType,
string policyType = PermConstants.DefaultPolicyType,
string effectType = PermConstants.DefaultPolicyEffectType,
string matcherType = PermConstants.DefaultMatcherType)
{
string matcher = model.Sections.GetValue(PermConstants.Section.MatcherSection, matcherType);
return CreateWithMatcher(model, matcher, requestType, policyType, effectType);
}
public static EnforceView CreateWithMatcher(
IModel model,
string matcher,
string requestType = PermConstants.DefaultRequestType,
string policyType = PermConstants.DefaultPolicyType,
string effectType = PermConstants.DefaultPolicyEffectType)
{
matcher = matcher.Replace('\'', '"');
IReadOnlyAssertion requestAssertion = model.Sections.GetRequestAssertion(requestType);
PolicyAssertion policyAssertion = model.Sections.GetPolicyAssertion(policyType);
IReadOnlyAssertion effectAssertion = model.Sections.GetPolicyEffectAssertion(effectType);
EnforceView view = new()
{
RequestType = requestType,
RequestAssertion = requestAssertion,
// TODO: ToImmutableArray dot support .NET 4.5.2
RequestTokens = requestAssertion.Tokens.Keys.ToArray(),
PolicyType = policyType,
PolicyAssertion = policyAssertion,
// TODO: ToImmutableArray dot support .NET 4.5.2
PolicyTokens = policyAssertion.Tokens.Keys.ToArray(),
Matcher = matcher,
HasEval = StringUtil.HasEval(matcher),
HasRequestParameter = matcher.Contains($"{requestType}."),
HasPolicyParameter = matcher.Contains($"{policyType}."),
Effect = effectAssertion.Value,
EffectExpressionType = DefaultEffector.ParseEffectExpressionType(effectAssertion.Value),
HasEffect = policyAssertion.TryGetTokenIndex("eft", out int effectIndex),
EffectIndex = effectIndex,
HasPriority = policyAssertion.TryGetTokenIndex("priority", out int priorityIndex),
PriorityIndex = priorityIndex,
};
if (StringUtil.TryGetEvalRuleNames(view.Matcher, out IEnumerable<string> ruleNames))
{
var evalRules = new Dictionary<string, int>();
foreach (string ruleName in ruleNames)
{
string ruleNameEnum = ruleName.Replace($"{view.PolicyType}.", string.Empty);
if (view.PolicyAssertion.Tokens.TryGetValue(ruleNameEnum, out int ruleIndex) is false)
{
throw new ArgumentException(
"Please make sure rule exists in policy when using eval() in matcher");
}
evalRules[ruleName] = ruleIndex;
}
view.EvalRules = evalRules;
}
view.SupportGeneric = Request.SupportGeneric(view.RequestTokens.Count) &&
Policy.SupportGeneric(view.PolicyTokens.Count);
// TransformedMatcher will be dynamic set when has eval
if (view.HasEval is false)
{
view.TransformedMatcher = TransformMatcher(view, view.Matcher);
}
return view;
}
[SuppressMessage("ReSharper", "LoopCanBeConvertedToQuery")]
[SuppressMessage("ReSharper", "UseDeconstruction")]
public static string TransformMatcher(in EnforceView view, string matcher)
{
string perfix = @"(?<=(\s|^|\||&|!|=|\(|\)|<|>|,|\+|-|\*|\/|\\|\[)\s*)";
string suffix = @"(?=\s*(\s|$|\||&|!|=|\(|\)|<|>|,|\+|-|\*|\/|\\|\[|\]|\.|in))";
if (view.SupportGeneric is false)
{
foreach (KeyValuePair<string, int> tokenPair in view.RequestAssertion.Tokens)
{
Regex reg = new Regex(perfix + $@"{view.RequestType}\.{tokenPair.Key}" + suffix);
matcher = reg.Replace(matcher, $"{view.RequestType}[{tokenPair.Value}]");
}
foreach (KeyValuePair<string, int> tokenPair in view.PolicyAssertion.Tokens)
{
Regex reg = new Regex(perfix + $@"{view.PolicyType}\.{tokenPair.Key}" + suffix);
matcher = reg.Replace(matcher, $"{view.PolicyType}[{tokenPair.Value}]");
}
return matcher;
}
foreach (KeyValuePair<string, int> tokenPair in view.RequestAssertion.Tokens)
{
Regex reg = new Regex(perfix + $@"{view.RequestType}\.{tokenPair.Key}" + suffix);
matcher = reg.Replace(matcher, $"{view.RequestType}.Value{tokenPair.Value + 1}");
}
foreach (KeyValuePair<string, int> tokenPair in view.PolicyAssertion.Tokens)
{
Regex reg = new Regex(perfix + $@"{view.PolicyType}\.{tokenPair.Key}" + suffix);
matcher = reg.Replace(matcher, $"{view.PolicyType}.Value{tokenPair.Value + 1}");
}
return matcher;
}
}
}