Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
zhabis committed Jul 12, 2023
1 parent d93491d commit db7c259
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 56 deletions.
90 changes: 50 additions & 40 deletions src/Azos/Conf/MacroRunner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,25 +33,13 @@ public interface IMacroRunner
[Serializable]
public class DefaultMacroRunner : IMacroRunner
{
#region CONSTS

public const string AS_PREFIX = "as-";

#endregion

#region STATIC

private static DefaultMacroRunner s_Instance = new DefaultMacroRunner();

private DefaultMacroRunner() { }

/// <summary>
/// Returns a singleton class instance
/// </summary>
public static DefaultMacroRunner Instance
{
get { return s_Instance; }
}
/// <summary>Returns a singleton class instance </summary>
public static DefaultMacroRunner Instance => s_Instance;

/// <summary>
/// Returns a string value converted to desired type with optional default and format
Expand Down Expand Up @@ -89,7 +77,6 @@ public static string GetValueAs(string value, string type, string dflt = null, s
else
return result.ToString();
}
#endregion

/// <summary>
/// Virtual method to run the named Macro using the provided input section node, input string, params section node, and context object
Expand All @@ -107,43 +94,66 @@ public virtual string Run(IConfigSectionNode node, string inputValue, string mac
macroParams.Navigate("$fmt|$format").Value);

}
else if (string.Equals(macroName, "now", StringComparison.InvariantCultureIgnoreCase))
else if (macroName.EqualsIgnoreCase("now"))
{
var utc = macroParams.AttrByName("utc").ValueAsBool(false);
return Macro_now(macroParams, context);
}
else if (macroName.EqualsIgnoreCase("ctx-name"))
{
if (context is Collections.INamed)
return ((Collections.INamed)context).Name;
}
else if (macroName.EqualsIgnoreCase("decipher")) //#870
{
return Macro_decipher(node, inputValue, macroName, macroParams, context);
}


var fmt = macroParams.Navigate("$fmt|$format").ValueAsString();
return inputValue;
}

public virtual string Macro_now(IConfigSectionNode macroParams, object context)
{
var utc = macroParams.AttrByName("utc").ValueAsBool(false);

var valueAttr = macroParams.AttrByName("value");
var fmt = macroParams.Navigate("$fmt|$format").ValueAsString();

var valueAttr = macroParams.AttrByName("value");

var now = Ambient.UTCNow;
if (!utc)

var now = Ambient.UTCNow;
if (!utc)
{
ILocalizedTimeProvider timeProvider = context as ILocalizedTimeProvider;
if (timeProvider == null && context is IApplicationComponent cmp)
{
ILocalizedTimeProvider timeProvider = context as ILocalizedTimeProvider;
if (timeProvider == null && context is IApplicationComponent cmp)
{
timeProvider = cmp.ComponentDirector as ILocalizedTimeProvider;
if (timeProvider == null) timeProvider = cmp.App;
}

now = timeProvider != null ? timeProvider.LocalizedTime : now.ToLocalTime();
timeProvider = cmp.ComponentDirector as ILocalizedTimeProvider;
if (timeProvider == null) timeProvider = cmp.App;
}

// We inspect the "value" param that may be provided for testing purposes
if (valueAttr.Exists)
now = valueAttr.Value.AsDateTimeFormat(now, fmt,
utc ? DateTimeStyles.AssumeUniversal : DateTimeStyles.AssumeLocal);

return fmt == null ? now.ToString() : now.ToString(fmt);
now = timeProvider != null ? timeProvider.LocalizedTime : now.ToLocalTime();
}
else if (string.Equals(macroName, "ctx-name", StringComparison.InvariantCultureIgnoreCase))

// We inspect the "value" param that may be provided for testing purposes
if (valueAttr.Exists)
now = valueAttr.Value.AsDateTimeFormat(now, fmt,
utc ? DateTimeStyles.AssumeUniversal : DateTimeStyles.AssumeLocal);

return fmt == null ? now.ToString() : now.ToString(fmt);
}

//#870
public virtual string Macro_decipher(IConfigSectionNode node, string inputValue, string macroName, IConfigSectionNode macroParams, object context)
{
if (inputValue.IsNullOrWhiteSpace()) //inputValue takes precedence
{
if (context is Collections.INamed)
return ((Collections.INamed)context).Name;
inputValue = macroParams.ValOf("value", "val", "v");//this is used if input value is empty
}


return inputValue;
var algorithmName = macroParams.ValOf("algorithm", "alg", "a");//this may be blank
var toString = macroParams.Of("string", "str").ValueAsBool(false);//true to decode into string vs base:64 byte array
var result = Security.TheSafe.DecipherConfigValue(inputValue, toString, algorithmName);
return result;
}
}

Expand Down
45 changes: 29 additions & 16 deletions src/Azos/Security/TheSafe.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,59 +20,72 @@ public static class TheSafe
{
/// <summary>
/// If this flag is set on the current call scope, authorizes access to safe
/// decipher method, otherwise <see cref="DecipherConfigValue(string, string)"/>
/// decipher method, otherwise <see cref="DecipherConfigValue(string, bool, string)"/>
/// would fail with <see cref="AccessToTheSafeDeniedException"/>
/// </summary>
public static readonly Atom SAFE_CONFIG_ACCESS_FLAG = Atom.Encode("safeconf");

/// <summary>
/// If this flag is set on the current call scope, authorizes access to safe
/// decipher method, otherwise <see cref="DecipherConfigValue(string, string)"/>
/// decipher method, otherwise <see cref="Decipher(byte[], string)"/>
/// would fail with <see cref="AccessToTheSafeDeniedException"/>
/// </summary>
public static readonly Atom SAFE_GENERAL_ACCESS_FLAG = Atom.Encode("safegen");


/// <summary>
/// Using the specified named key deciphers a `byte[]` value encoded as a string (using `base64:` or byte array syntax)
/// Using the specified named algorithm deciphers a `byte[]` value encoded as a string (using `base64:` or byte array syntax)
/// <see cref="StringValueConversion.AsByteArray(string, byte[])"/>
/// into another `byte[]` value encoded as a string with `base64:` prefix.
/// Returns null if value is invalid or key is not found or mismatches the value.
/// For security purposes this method does not throw exceptions explaining why the value has not been deciphered
/// Returns null if value is invalid or algorithm is not found or mismatches the value.
/// For security purposes this method does not throw exceptions explaining why the value has not been deciphered.
/// An algorithm name can be null which means the default algorithm
/// </summary>
public static string DecipherConfigValue(string key, string value)
/// <param name="value">Config value to decipher. Null or empty returns null</param>
/// <param name="toString">If true returns a string read from decoded byte[] using UTF8, otherwise returns base64-encoded byte array</param>
/// <param name="algorithmName">Name of algorithm, if null then the default algorithm is assumed</param>
public static string DecipherConfigValue(string value, bool toString, string algorithmName = null)
{
if (value.IsNullOrWhiteSpace()) return null;
key.NonBlank(nameof(key));

if (!SecurityFlowScope.CheckFlag(SAFE_CONFIG_ACCESS_FLAG))
throw new AccessToTheSafeDeniedException(StringConsts.SECURITY_ACCESS_TO_THESAFE_DENIED_ERROR.Args($"{nameof(SecurityFlowScope)}({nameof(TheSafe)}.{nameof(SAFE_CONFIG_ACCESS_FLAG)})"));

var ain = value.AsByteArray();
var aout = decipher(key, ain);
return StringValueConversion.BASE64_VALUE_PREFIX + ain.ToWebSafeBase64();
var aout = decipher(ain, algorithmName);

if (aout == null) return null;

if (toString)
return ain.FromUTF8Bytes();
else
return StringValueConversion.BASE64_VALUE_PREFIX + ain.ToWebSafeBase64();
}

/// <summary>
/// Using the specified named key deciphers the value.
/// Returns null if value is invalid or key is not found or mismatches the value.
/// For security purposes this method does not throw exceptions explaining why the value has not been deciphered
/// Using the specified named algorithm deciphers the value.
/// Returns null if value is invalid or algorithm is not found or mismatches the value.
/// For security purposes this method does not throw exceptions explaining why the value has not been deciphered.
/// A null algorithm name means the default algorithm
/// </summary>
public static byte[] Decipher(string key, byte[] value)
public static byte[] Decipher(byte[] value, string algorithmName = null)
{
if (value == null) return null;
key.NonBlank(nameof(key));

if (!SecurityFlowScope.CheckFlag(SAFE_GENERAL_ACCESS_FLAG))
throw new AccessToTheSafeDeniedException(StringConsts.SECURITY_ACCESS_TO_THESAFE_DENIED_ERROR.Args($"{nameof(SecurityFlowScope)}({nameof(TheSafe)}.{nameof(SAFE_GENERAL_ACCESS_FLAG)})"));

return decipher(key, value);
return decipher(value, algorithmName);
}

private static byte[] decipher(string key, byte[] value)
private static byte[] decipher(byte[] value, string algorithmName)
{
if (value == null) return null;

#region Temp code
var result = new byte[value.Length];
for(var i=0; i<value.Length; i++) result[result.Length-i-1] = value[i];
#endregion Temp Code

return null;
}
Expand Down

0 comments on commit db7c259

Please sign in to comment.