Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion ConfigCrypter.Console/Options/CommandlineOptions.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using CommandLine;
using Newtonsoft.Json;

namespace ConfigCrypter.Console.Options
{
Expand All @@ -24,10 +25,14 @@ public class CommandlineOptions

[Option("format", Default = ConfigFormat.Json, HelpText = "The format of the config file.")]
public ConfigFormat ConfigFormat { get; set; }

[Option('x', "separator", Required = false, HelpText = "Split the key (if the key has multiple value).", Default = ';')]
public char Separator { get; set; }

}

public enum ConfigFormat
{
Json
}
}
}
4 changes: 2 additions & 2 deletions ConfigCrypter.Console/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ static void Main(string[] args)
.WithParsed<EncryptOptions>(opts =>
{
var crypter = CreateCrypter(opts);
crypter.EncryptKeyInFile(opts.ConfigFile, opts.Key);
crypter.EncryptKeyInFile(opts.ConfigFile, opts.Key, opts.Separator);
})
.WithParsed<DecryptOptions>(opts =>
{
var crypter = CreateCrypter(opts);
crypter.DecryptKeyInFile(opts.ConfigFile, opts.Key);
crypter.DecryptKeyInFile(opts.ConfigFile, opts.Key, opts.Separator);
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,52 @@ public void EncryptKey_WithValidJson_CallsEncryptStringOnCrypter()
Assert.Equal("ValueToEncrypt_encrypted", parsedJson.Key);
}

[Fact]
public void EncryptKeys_WithValidJson_CallsEncryptStringOnCrypter()
{
var crypterMock = Mocks.Crypter;
var jsonCrypter = new JsonConfigCrypter(crypterMock.Object);
var json = JsonConvert.SerializeObject(new TestAppSettings() { Key = "ValueToEncrypt", AdditionalKey = "AdditionalKeyToEncrypt" });

var encryptedJson = jsonCrypter.EncryptKey(json, "Key;AdditionalKey");
var parsedJson = JsonConvert.DeserializeObject<TestAppSettings>(encryptedJson);

// Additionally we test if the test crypter does its job.
Assert.Equal("ValueToEncrypt_encrypted", parsedJson.Key);
Assert.Equal("AdditionalKeyToEncrypt_encrypted", parsedJson.AdditionalKey);
}

[Theory]
[InlineData('|')]
[InlineData(',')]
public void EncryptKeys_WithDifferentSeparator_WithValidJson_CallsEncryptStringOnCrypter(char separator)
{
var crypterMock = Mocks.Crypter;
var jsonCrypter = new JsonConfigCrypter(crypterMock.Object);
var json = JsonConvert.SerializeObject(new TestAppSettings() { Key = "ValueToEncrypt", AdditionalKey = "AdditionalKeyToEncrypt" });

var encryptedJson = jsonCrypter.EncryptKey(json, $"Key{separator}AdditionalKey", separator);
var parsedJson = JsonConvert.DeserializeObject<TestAppSettings>(encryptedJson);

// Additionally we test if the test crypter does its job.
Assert.Equal("ValueToEncrypt_encrypted", parsedJson.Key);
Assert.Equal("AdditionalKeyToEncrypt_encrypted", parsedJson.AdditionalKey);
}

[Fact]
public void EncryptKeys_WithEmptyFieldAndWithValidJson_CallsEncryptStringOnCrypter()
{
var crypterMock = Mocks.Crypter;
var jsonCrypter = new JsonConfigCrypter(crypterMock.Object);
var json = JsonConvert.SerializeObject(new TestAppSettings() { Key = "ValueToEncrypt" });

var encryptedJson = jsonCrypter.EncryptKey(json, "Key;;");
var parsedJson = JsonConvert.DeserializeObject<TestAppSettings>(encryptedJson);

// Additionally we test if the test crypter does its job.
Assert.Equal("ValueToEncrypt_encrypted", parsedJson.Key);
}

[Fact]
public void DecryptKey_WithValidJson_CallsDecryptStringOnCrypter()
{
Expand All @@ -36,6 +82,52 @@ public void DecryptKey_WithValidJson_CallsDecryptStringOnCrypter()
Assert.Equal("ValueToEncrypt", parsedJson.Key);
}

[Fact]
public void DecryptKeys_WithValidJson_CallsEncryptStringOnCrypter()
{
var crypterMock = Mocks.Crypter;
var jsonCrypter = new JsonConfigCrypter(crypterMock.Object);
var json = JsonConvert.SerializeObject(new TestAppSettings() { Key = "ValueToEncrypt_encrypted", AdditionalKey = "AdditionalKeyToEncrypt_encrypted" });

var encryptedJson = jsonCrypter.DecryptKey(json, "Key;AdditionalKey");
var parsedJson = JsonConvert.DeserializeObject<TestAppSettings>(encryptedJson);

// Additionally we test if the test crypter does its job.
Assert.Equal("ValueToEncrypt", parsedJson.Key);
Assert.Equal("AdditionalKeyToEncrypt", parsedJson.AdditionalKey);
}

[Theory]
[InlineData('|')]
[InlineData(',')]
public void DecryptKey_WithDifferentSeparator_WithValidJson_CallsEncryptStringOnCrypter(char separator)
{
var crypterMock = Mocks.Crypter;
var jsonCrypter = new JsonConfigCrypter(crypterMock.Object);
var json = JsonConvert.SerializeObject(new TestAppSettings() { Key = "ValueToEncrypt_encrypted", AdditionalKey = "AdditionalKeyToEncrypt_encrypted" });

var encryptedJson = jsonCrypter.DecryptKey(json, $"Key{separator}AdditionalKey", separator);
var parsedJson = JsonConvert.DeserializeObject<TestAppSettings>(encryptedJson);

// Additionally we test if the test crypter does its job.
Assert.Equal("ValueToEncrypt", parsedJson.Key);
Assert.Equal("AdditionalKeyToEncrypt", parsedJson.AdditionalKey);
}

[Fact]
public void DecryptKeys_WithEmptyFieldAndWithValidJson_CallsEncryptStringOnCrypter()
{
var crypterMock = Mocks.Crypter;
var jsonCrypter = new JsonConfigCrypter(crypterMock.Object);
var json = JsonConvert.SerializeObject(new TestAppSettings() { Key = "ValueToEncrypt_encrypted" });

var encryptedJson = jsonCrypter.DecryptKey(json, "Key;;");
var parsedJson = JsonConvert.DeserializeObject<TestAppSettings>(encryptedJson);

// Additionally we test if the test crypter does its job.
Assert.Equal("ValueToEncrypt", parsedJson.Key);
}

[Fact]
public void Dispose_CallsDisposeOnCrypter()
{
Expand All @@ -47,4 +139,4 @@ public void Dispose_CallsDisposeOnCrypter()
crypterMock.Verify(crypter => crypter.Dispose());
}
}
}
}
3 changes: 2 additions & 1 deletion ConfigCrypter.Tests/TestAppSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
public class TestAppSettings
{
public string Key { get; set; }
public string AdditionalKey { get; set; }
}
}
}
4 changes: 2 additions & 2 deletions ConfigCrypter/ConfigCrypters/IConfigCrypter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public interface IConfigCrypter : IDisposable
/// <param name="configKey">Key of the config entry.</param>
/// <returns>The content of the config file where the key has been decrypted.</returns>
/// <remarks>It up to the implementer how to interpret the format of the config key.</remarks>
string DecryptKey(string configFileContent, string configKey);
string DecryptKey(string configFileContent, string configKey, char separators = ';');

/// <summary>
/// Encrypts the key in the given content of a config file.
Expand All @@ -23,6 +23,6 @@ public interface IConfigCrypter : IDisposable
/// <param name="configKey">Key of the config entry.</param>
/// <returns>The content of the config file where the key has been encrypted.</returns>
/// <remarks>It up to the implementer how to interpret the format of the config key.</remarks>
string EncryptKey(string configFileContent, string configKey);
string EncryptKey(string configFileContent, string configKey, char separators = ';');
}
}
56 changes: 39 additions & 17 deletions ConfigCrypter/ConfigCrypters/Json/JsonConfigCrypter.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Text;
using DevAttic.ConfigCrypter.Crypters;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
Expand All @@ -25,17 +26,28 @@ public JsonConfigCrypter(ICrypter crypter)
/// Decrypts the key in the given content of a config file.
/// </summary>
/// <param name="configFileContent">String content of a config file.</param>
/// <param name="configKey">Key of the config entry. The key has to be in JSONPath format.</param>
/// <param name="configKeys">Key of the config entry. The key has to be in JSONPath format.</param>
/// <param name="separator">Split the key if it has multiple value.</param>
/// <returns>The content of the config file where the key has been decrypted.</returns>
public string DecryptKey(string configFileContent, string configKey)
public string DecryptKey(string configFileContent, string configKeys, char separator = ';')
{
var (parsedConfig, settingsToken) = ParseConfig(configFileContent, configKey);
var configKeyList = configKeys.Split(separator);

var encryptedValue = _crypter.DecryptString(settingsToken.Value<string>());
settingsToken.Replace(encryptedValue);
var newConfigContent = parsedConfig.ToString(Formatting.Indented);
var parsedJson = JObject.Parse(configFileContent);

foreach (var configKey in configKeyList)
{
if (string.IsNullOrWhiteSpace(configKey)) continue;

var settingsToken = ParseConfig(parsedJson, configKey);

var decryptedValue = _crypter.DecryptString(settingsToken.Value<string>());
settingsToken.Replace(decryptedValue);
}

var newConfigContent = parsedJson.ToString(Formatting.Indented);
return newConfigContent;

}

public void Dispose()
Expand All @@ -48,16 +60,27 @@ public void Dispose()
/// Encrypts the key in the given content of a config file.
/// </summary>
/// <param name="configFileContent">String content of a config file.</param>
/// <param name="configKey">Key of the config entry. The key has to be in JSONPath format.</param>
/// <param name="configKeys">Key of the config entry. The key has to be in JSONPath format.</param>
/// <param name="separator">Split the key by semicolon(;) if it has multiple value.</param>
/// <returns>The content of the config file where the key has been encrypted.</returns>
public string EncryptKey(string configFileContent, string configKey)
public string EncryptKey(string configFileContent, string configKeys, char separator = ';')
{
var (parsedConfig, settingsToken) = ParseConfig(configFileContent, configKey);

var encryptedValue = _crypter.EncryptString(settingsToken.Value<string>());
settingsToken.Replace(encryptedValue);
var newConfigContent = parsedConfig.ToString(Formatting.Indented);
var configKeyList = configKeys.Split(separator);

var parsedJson = JObject.Parse(configFileContent);

foreach (var configKey in configKeyList)
{
if (string.IsNullOrWhiteSpace(configKey)) continue;

var settingsToken = ParseConfig(parsedJson, configKey);

var encryptedValue = _crypter.EncryptString(settingsToken.Value<string>());
settingsToken.Replace(encryptedValue);
}

var newConfigContent = parsedJson.ToString(Formatting.Indented);
return newConfigContent;
}

Expand All @@ -69,17 +92,16 @@ protected virtual void Dispose(bool disposing)
}
}

private (JObject ParsedConfig, JToken Key) ParseConfig(string json, string configKey)
private JToken ParseConfig(JToken json, string configKey)
{
var parsedJson = JObject.Parse(json);
var keyToken = parsedJson.SelectToken(configKey);
var keyToken = json.SelectToken(configKey);

if (keyToken == null)
{
throw new InvalidOperationException($"The key {configKey} could not be found.");
}

return (parsedJson, keyToken);
return keyToken;
}
}
}
}
10 changes: 6 additions & 4 deletions ConfigCrypter/ConfigFileCrypter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,11 @@ public ConfigFileCrypter(IConfigCrypter configCrypter, ConfigFileCrypterOptions
/// </summary>
/// <param name="filePath">Path of the configuration file.</param>
/// <param name="configKey">Key to decrypt, passed in a format the underlying config crypter understands.</param>
public void DecryptKeyInFile(string filePath, string configKey)
/// <param name="separator">Split the key if it has multiple value.</param>
public void DecryptKeyInFile(string filePath, string configKey, char separator = ';')
{
var configContent = File.ReadAllText(filePath);
var decryptedConfigContent = _configCrypter.DecryptKey(configContent, configKey);
var decryptedConfigContent = _configCrypter.DecryptKey(configContent, configKey, separator);

var targetFilePath = GetDestinationConfigPath(filePath, _options.DecryptedConfigPostfix);
File.WriteAllText(targetFilePath, decryptedConfigContent);
Expand All @@ -47,10 +48,11 @@ public void DecryptKeyInFile(string filePath, string configKey)
/// </summary>
/// <param name="filePath">Path of the configuration file.</param>
/// <param name="configKey">Key to encrypt, passed in a format the underlying config crypter understands.</param>
public void EncryptKeyInFile(string filePath, string configKey)
/// <param name="separator">Split the key if it has multiple value.</param>
public void EncryptKeyInFile(string filePath, string configKey, char separator = ';')
{
var configContent = File.ReadAllText(filePath);
var encryptedConfigContent = _configCrypter.EncryptKey(configContent, configKey);
var encryptedConfigContent = _configCrypter.EncryptKey(configContent, configKey, separator);

var targetFilePath = GetDestinationConfigPath(filePath, _options.EncryptedConfigPostfix);
File.WriteAllText(targetFilePath, encryptedConfigContent);
Expand Down
15 changes: 13 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ If you now have your certificate you need to decide what keys you want to encryp
```json
{
"Nested": {
"KeyToEncrypt": "This will be encrypted"
"KeyToEncrypt": "This will be encrypted",
"AdditionalKeyToEncrypt": "This will be encrypted"
}
}
```
Expand All @@ -52,6 +53,15 @@ If you want to prevent the creation of a new file you can simply pass --replace
To decrypt the file again you can simply execute:
`config-crypter decrypt -p c:\path\to\cert.pfx -f c:\path\to\config_encrypted.json -k "Nested.KeyToEncrypt"`

### Multiple Keys Encryption in Single Command
You can use semicolon ";" as a separator by default. Apart from that you can also specify the separator that you want to use.

To encrypt our keys from above we simple execute:
`config-crypter encrypt -p c:\path\to\cert.pfx -f c:\path\to\config.json -k "Nested.KeyToEncrypt;Nested.AdditionalKeyToEncrypt"`.

To decrypt the file again you can simply execute:
`config-crypter decrypt -p c:\path\to\cert.pfx -f c:\path\to\config_encrypted.json -k "Nested.KeyToEncrypt;Nested.AdditionalKeyToEncrypt"`

## Command line arguments
The following command line arguments can be passed for the encrypt and decrypt command.
```
Expand All @@ -60,6 +70,7 @@ The following command line arguments can be passed for the encrypt and decrypt c
-k, --key Required. The key to encrypt in the config file.
-f, --file Required. The path to the config file.
-r, --replace (Default: false) Replaces the original file if passed as parameter.
-x, --separator (Default : ';') Split the key (if the key has multiple value).
--format (Default: Json) The format of the config file.
--help Display this help screen.
--version Display version information.
Expand Down Expand Up @@ -130,4 +141,4 @@ To generate a certificate you could use the following commands:

`openssl req -new -x509 -nodes -sha1 -days 365 -key private.key > public.cer`

`openssl pkcs12 -export -in public.cer -inkey private.key -out cert.pfx`
`openssl pkcs12 -export -in public.cer -inkey private.key -out cert.pfx`