Skip to content

Instantly share code, notes, and snippets.

@Lachee
Last active August 20, 2020 05:33
Show Gist options
  • Save Lachee/c4143fa45d5be27403c12efff32de26b to your computer and use it in GitHub Desktop.
Save Lachee/c4143fa45d5be27403c12efff32de26b to your computer and use it in GitHub Desktop.
LazyKey is a class that allows for JSON configuration files that utilise separate files for secret tokens. I use this a lot with my bots so I can have a universal configuration, but gitignore .key. It keeps the pattern matching between the Config.cs and the Config.json, by allowing implicit conversion from a string filename. There was the potent…
class Config
{
public string Project { get; set; } = "AProject";
public string Repository { get; set; } = "ARepo";
public string Organization { get; set; } = "https://dev.azure.com/org";
public LazyKey Credentials { get; set; } = "devops.key";
}
{
"Project": "AProject",
"Repository": "ARepo",
"Organization": "https://dev.azure.com/org",
"Credentials": "devops.key"
}
[Newtonsoft.Json.JsonConverter(typeof(LazyKey.Converter))]
public class LazyKey
{
/// <summary>
/// The file path to load the key from
/// </summary>
public string FilePath { get; set; }
/// <summary>
/// Should the value be cached in memory. This should be enabled if the value is used a lot throughout the application.
/// </summary>
public bool Cache { get => _cache; set { _cache = value; if (!value) _cachedValue = null; } }
private bool _cache = false;
private string _cachedValue = null;
/// <summary>
/// Gets the key value.
/// <seealso cref="LoadSecret"/>
/// </summary>
public string Secret
{
get
{
if (Cache && !string.IsNullOrEmpty(_cachedValue)) return _cachedValue;
return LoadSecret();
}
set
{
StoreSecret(value);
}
}
/// <summary>
/// Creates a new instance
/// </summary>
/// <param name="filePath">The filePath that the secret is located in</param>
/// <param name="cache">Cache the secret?</param>
public LazyKey(string filePath, bool cache = true)
{
FilePath = filePath;
Cache = cache;
_cachedValue = null;
}
/// <summary>
/// Lazy Loads the key
/// </summary>
/// <param name="ignoreCache">Should the cache be ignored and reloaded.</param>
/// <returns>string key</returns>
public string LoadSecret()
{
//Otherwise load it and store the cache if we can
string value = FilePath != null ? System.IO.File.ReadAllText(FilePath) : null;
if (Cache) _cachedValue = value;
return value;
}
/// <summary>
/// Writes the secret to the file path
/// </summary>
/// <param name="secret"></param>
public void StoreSecret(string secret)
{
if (FilePath == null) throw new System.InvalidOperationException("Cannot store the secret as there is no FilePath.");
System.IO.File.WriteAllText(FilePath, secret);
if (Cache) _cachedValue = secret;
}
public override string ToString() { return FilePath; }
//The string implicits should not differ from each other. Using LazyKey lk = (string)(new LazyKey("s")); should return the same lazy key.
//public static implicit operator string(LazyKey key) { return key.GetSecret(); }
[System.Obsolete("Use ToString instead")] public static implicit operator string(LazyKey key) { return key.FilePath; }
/** [System.Obsolete("Use the constructor instead")] */ public static implicit operator LazyKey(string filePath) { return new LazyKey(filePath); }
private class Converter : Newtonsoft.Json.JsonConverter
{
public override bool CanConvert(System.Type objectType) { return objectType == typeof(LazyKey); }
public override bool CanRead => true;
public override bool CanWrite => true;
public override void WriteJson(Newtonsoft.Json.JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer) { writer.WriteValue(((LazyKey)value).FilePath); }
public override object ReadJson(Newtonsoft.Json.JsonReader reader, System.Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer)
{
if (existingValue == null) return new LazyKey(reader.Value?.ToString());
((LazyKey)existingValue).FilePath = reader.Value?.ToString();
return existingValue;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment