blob: eeeb870de6ae87f88569385d605ff605fec08eec [file] [log] [blame]
using System;
using System.Collections.Generic;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using Microsoft.Deployment.WindowsInstaller;
namespace CustomAction
{
public class CustomActions
{
[CustomAction]
public static ActionResult InitCookieValue(Session session)
{
try
{
byte[] buffer = new byte[16];
RandomNumberGenerator rng = RNGCryptoServiceProvider.Create();
rng.GetBytes(buffer);
session["COOKIEVALUE"] = BitConverter.ToString(buffer).Replace("-", String.Empty);
}
catch (Exception ex)
{
session.Log("ERROR in custom action InitCookieValue {0}",
ex.ToString());
return ActionResult.Failure;
}
return ActionResult.Success;
}
[CustomAction]
public static ActionResult WriteAdminIniFile(Session session)
{
try
{
if (!File.Exists(session.CustomActionData["ADMINCONFIGFILE"]))
{
using (StreamWriter writer = new StreamWriter(session.CustomActionData["ADMINCONFIGFILE"]))
{
writer.WriteLine("; CouchDB Windows installer-generated admin user");
writer.WriteLine("[admins]");
writer.WriteLine($"{session.CustomActionData["ADMINUSER"]} = {session.CustomActionData["ADMINPASSWORD"]}");
}
}
}
catch (Exception ex)
{
session.Log("ERROR in custom action WriteAdminIniFile {0}",
ex.ToString());
return ActionResult.Failure;
}
return ActionResult.Success;
}
[CustomAction]
public static ActionResult WriteCookieToVmArgs(Session session)
{
try
{
string VMARGSFILE = Path.Combine(session.CustomActionData["ETCDIR"], "vm.args");
if (File.Exists(VMARGSFILE))
{
session.Log("Patching erlang cookie in existing vm.args file");
PatchErlangCookie(session, VMARGSFILE);
}
string VMFile = Path.Combine(session.CustomActionData["ETCDIR"], "vm.args.dist");
byte[] VMBuffer = File.ReadAllBytes(VMFile);
string VMText = Regex.Replace(Encoding.UTF8.GetString(VMBuffer), @"# -setcookie", $"-setcookie {session.CustomActionData["COOKIEVALUE"]}");
File.WriteAllBytes(VMFile, Encoding.UTF8.GetBytes(VMText));
}
catch (Exception ex)
{
session.Log("ERROR in custom action WriteCookieToVmArgs {0}",
ex.ToString());
return ActionResult.Failure;
}
return ActionResult.Success;
}
private static void PatchErlangCookie(Session session, string file)
{
//Patching erlang cookie
byte[] VMBuffer = File.ReadAllBytes(file);
string VMText = Regex.Replace(Encoding.UTF8.GetString(VMBuffer), @"-setcookie \S*", $"-setcookie {session.CustomActionData["COOKIEVALUE"]}");
File.WriteAllBytes(file, Encoding.UTF8.GetBytes(VMText));
}
private static void PatchErlangInterface(Session session, string file)
{
byte[] VMBuffer = File.ReadAllBytes(file);
//Patching erlang interface
string pattern = @"-kernel inet_dist_use_interface";
string input = Encoding.UTF8.GetString(VMBuffer);
Match m = Regex.Match(input, pattern, RegexOptions.IgnoreCase);
if (!m.Success)
{
session.Log("Pattern \"inet_dist_use_interface\" not found, appending fix.");
using (StreamWriter sw = File.AppendText(file))
{
sw.WriteLine();
sw.WriteLine("# Which interfaces should the node listen on?");
sw.WriteLine("-kernel inet_dist_use_interface {127,0,0,1}");
sw.Close();
}
}
else
{
session.Log("Pattern \"inet_dist_use_interface\" found, skipping.");
}
}
[CustomAction]
public static ActionResult MaybeCopyIniFiles(Session session)
{
try
{
string[] files = new string[2];
files[0] = "vm.args";
files[1] = "local.ini";
string VMARGSFILE = Path.Combine(session.CustomActionData["ETCDIR"], files[0]);
if (File.Exists(VMARGSFILE))
{
session.Log("Patching erlang interface in existing vm.args file");
PatchErlangInterface(session, VMARGSFILE);
}
foreach (string file in files)
{
if (!File.Exists(Path.Combine(session.CustomActionData["ETCDIR"], file)))
{
File.Copy(
Path.Combine(session.CustomActionData["ETCDIR"], file + ".dist"),
Path.Combine(session.CustomActionData["ETCDIR"], file)
);
}
}
}
catch (Exception ex)
{
session.Log("ERROR in custom action MaybeCopyIniFiles {0}",
ex.ToString());
return ActionResult.Failure;
}
return ActionResult.Success;
}
[CustomAction]
public static ActionResult MaybeRemoveUserConfig(Session session)
{
try
{
string[] files = new string[2];
files[0] = "vm.args";
files[1] = "local.ini";
foreach (string file in files)
{
if (File.Exists(Path.Combine(session.CustomActionData["ETCDIR"], file)) &&
File.Exists(Path.Combine(session.CustomActionData["ETCDIR"], file + ".dist")))
{
if (GetChecksum(Path.Combine(session.CustomActionData["ETCDIR"], file)) ==
GetChecksum(Path.Combine(session.CustomActionData["ETCDIR"], file + ".dist")))
{
File.Delete(Path.Combine(session.CustomActionData["ETCDIR"], file));
}
}
}
}
catch (Exception ex)
{
session.Log("ERROR in custom action MaybeRemoveUserConfig {0}",
ex.ToString());
return ActionResult.Failure;
}
return ActionResult.Success;
}
private static string GetChecksum(string file)
{
using (FileStream stream = File.OpenRead(file))
{
SHA256CryptoServiceProvider sha = new SHA256CryptoServiceProvider();
byte[] checksum = sha.ComputeHash(stream);
return BitConverter.ToString(checksum).Replace("-", String.Empty);
}
}
}
}