-
Notifications
You must be signed in to change notification settings - Fork 4
/
ProtectProviderConfigurationData.cs
144 lines (113 loc) · 7.29 KB
/
ProtectProviderConfigurationData.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
using System;
using System.Linq;
using System.Text.RegularExpressions;
namespace Fededim.Extensions.Configuration.Protected
{
/// <summary>
/// A standard interface which must implement by an encryption/decryption provider
/// </summary>
public interface IProtectProvider
{
/// <summary>
/// This method encrypts a plain-text string
/// </summary>
/// <param name="plainTextValue">the plain-text string to be encrypted</param>
/// <returns>the encrypted string</returns>
String Encrypt(String plainTextValue);
/// <summary>
/// This method decrypts an encrypted string
/// </summary>
/// <param name="encryptedValue">the encrypted string to be decrypted</param>
/// <returns>the decrypted string</returns>
String Decrypt(String encryptedValue);
/// <summary>
/// This methods create a new <see cref="IProtectProvider"/> for supporting per configuration value encryption subkey (e.g. "subpurposes")
/// </summary>
/// <param name="subkey">the per configuration value encryption subkey</param>
/// <returns>a derived <see cref="IProtectProvider"/> based on the <see cref="subkey"/> parameter</returns>
IProtectProvider CreateNewProviderFromSubkey(string subkey);
}
/// <summary>
/// an abstract class for specifying the configuration data of the encryption/decryption provider
/// </summary>
public abstract class IProtectProviderConfigurationData
{
public const String DefaultProtectRegexString = "Protect(?<subPurposePattern>(:{(?<subPurpose>[^:}]+)})?):{(?<protectData>.*?)}";
public const String DefaultProtectedRegexString = "Protected(?<subPurposePattern>(:{(?<subPurpose>[^:}]+)})?):{(?<protectedData>.*?)}";
public const String DefaultProtectedReplaceString = "Protected${subPurposePattern}:{${protectedData}}";
/// <summary>
/// The actual provider performing the encryption/decryption, <see cref="IProtectProvider"/> interface
/// </summary>
public IProtectProvider ProtectProvider { get; protected set; }
/// <summary>
/// a regular expression which captures the data to be decrypted in a named group called protectData
/// </summary>
public Regex ProtectedRegex { get; protected set; }
/// <summary>
/// a regular expression which captures the data to be encrypted in a named group called protectData
/// </summary>
public Regex ProtectRegex { get; protected set; }
/// <summary>
/// a string replacement expression which captures the substitution which must be applied for transforming unencrypted tokenization <see cref="DefaultProtectRegexString" /> into an encrypted tokenization <see cref="DefaultProtectedRegexString" />
/// </summary>
public String ProtectedReplaceString { get; protected set; }
/// <summary>
/// A helper overridable method for checking that the configuation data is valid (e.g. ProtectProvider is not null, ProtectedRegex and ProtectRegex contains both a regex group named protectedData)
/// </summary>
public virtual void CheckConfigurationIsValid()
{
ProtectRegex = ProtectRegex ?? new Regex(DefaultProtectRegexString);
if (!ProtectRegex.GetGroupNames().Contains("protectData"))
throw new ArgumentException("ProtectRegex must contain a group named protectedData!", nameof(ProtectRegex));
ProtectedRegex = ProtectedRegex ?? new Regex(DefaultProtectedRegexString);
if (!ProtectedRegex.GetGroupNames().Contains("protectedData"))
throw new ArgumentException("ProtectedRegex must contain a group named protectedData!", nameof(ProtectedRegex));
ProtectedReplaceString = !String.IsNullOrEmpty(ProtectedReplaceString) ? ProtectedReplaceString : DefaultProtectedReplaceString;
if (!ProtectedReplaceString.Contains("${protectedData}"))
throw new ArgumentException("ProtectedReplaceString must contain ${protectedData}!", nameof(ProtectedReplaceString));
if (ProtectProvider == null)
throw new ArgumentException("ProtectProvider must not be null!", nameof(ProtectProvider));
}
}
/// <summary>
/// ProtectedConfigurationData is a custom data structure which stores all configuration options needed by ProtectedConfigurationBuilder and ProtectConfigurationProvider
/// </summary>
public class ProtectProviderConfigurationData : IProtectProviderConfigurationData
{
/// <summary>
/// Main constructor
/// </summary>
/// <param name="protectRegexString">a regular expression which captures the data to be encrypted in a named group called protectData</param>
/// <param name="protectedRegexString">a regular expression which captures the data to be decrypted in a named group called protectData</param>
/// <param name="protectedReplaceString">a string replacement expression which captures the substitution which must be applied for transforming unencrypted tokenization <see cref="DefaultProtectRegexString" /> into an encrypted tokenization <see cref="DefaultProtectedRegexString" /></param>
/// <param name="protectProvider">an IProtectProvider interface obtained from a one of the supported providers</param>
/// <exception cref="ArgumentException">thrown if the Regex does not containg a group named protectedData</exception>
public ProtectProviderConfigurationData(String protectRegexString, String protectedRegexString, String protectedReplaceString, IProtectProvider protectProvider)
{
if (!String.IsNullOrEmpty(protectRegexString))
ProtectRegex = new Regex(protectRegexString);
if (!String.IsNullOrEmpty(protectedRegexString))
ProtectedRegex = new Regex(protectedRegexString);
ProtectedReplaceString = protectedReplaceString;
ProtectProvider = protectProvider;
// check resulting configuration is valid, if it is not valid we raise an exception in order to be notified that something is wrong
CheckConfigurationIsValid();
}
/// <summary>
/// A static helper method which calculates the merge of the global and local protected configuration data. The resulting configuration is checked for validity inside <see cref="ProtectProviderConfigurationData"/> constructor.
/// </summary>
/// <param name="global">the global configuration data</param>
/// <param name="local">the local configuration data</param>
/// <returns></returns>
public static IProtectProviderConfigurationData Merge(IProtectProviderConfigurationData global, IProtectProviderConfigurationData local)
{
if (local == null)
return global;
if (global == null)
return local;
// perform merge
var result = new ProtectProviderConfigurationData(local.ProtectRegex?.ToString() ?? global.ProtectRegex?.ToString(), local.ProtectedRegex?.ToString() ?? global.ProtectedRegex?.ToString(), local.ProtectedReplaceString ?? global.ProtectedReplaceString, local.ProtectProvider ?? global.ProtectProvider);
return result;
}
}
}