Skip to content

Commit 8f83a2d

Browse files
test version
1 parent e59979e commit 8f83a2d

16 files changed

+658
-244
lines changed

1. LoadConfig.cs

+206
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
using BSS.Logging;
2+
using System;
3+
using System.IO;
4+
using System.Net;
5+
using System.Text.RegularExpressions;
6+
7+
#pragma warning disable CS8600
8+
#pragma warning disable CS8625
9+
10+
namespace CertBotHelper
11+
{
12+
internal static partial class Program
13+
{
14+
private const String REGEX_CERTBOT_IP = "^CertBot-IP\t*=(.+)$";
15+
private const String REGEX_SSH_USERNAME = "^SSH-Username\t*=(.+)$";
16+
private const String REGEX_SSH_PKEY_PATH = "^SSH-PrivateKeyPath\t*=(.+)$";
17+
private const String REGEX_REMOTE_CERTBOT_PATH = "^RemoteCertBotDirectory\t*=(.+)$";
18+
private const String REGEX_LOCAL_CERT_OUT_PATH = "^LocalCertificateDestinationPath\t*=(.+)$";
19+
private const String REGEX_NGINX_EXE_PATH = "^PathToNginx\\.exe\t*=(.+)$";
20+
private const String REGEX_RENEWAL_COMMAND = "^CertBotRenewalCommand\t*=(.+)$";
21+
22+
internal ref struct Configuration
23+
{
24+
internal String CertBotIP;
25+
internal String SSHUsername;
26+
internal String SSHPrivateKeyPath;
27+
internal String RemoteCertBotPath;
28+
internal String LocalCertificateOutputPath;
29+
internal String NginxPath;
30+
31+
internal String RenewalCommand;
32+
}
33+
34+
private static Boolean LoadConfig(String assemblyPath, out Configuration configuration)
35+
{
36+
configuration.CertBotIP = null;
37+
configuration.SSHUsername = null;
38+
configuration.SSHPrivateKeyPath = null;
39+
configuration.RemoteCertBotPath = null;
40+
configuration.LocalCertificateOutputPath = null;
41+
configuration.NginxPath = null;
42+
configuration.RenewalCommand = null;
43+
44+
if (!File.Exists(assemblyPath + "\\config.txt"))
45+
{
46+
try
47+
{
48+
File.WriteAllText(assemblyPath + "\\config.txt", "CertBot-IP\t\t\t\t\t\t=10.0.1.122\r\nSSH-Username\t\t\t\t\t=user\r\nSSH-PrivateKeyPath\t\t\t\t=C:\\nginx\\CertBot-Helper\\CertBot_Key\r\nRemoteCertBotDirectory\t\t\t=/home/user/CertBot/\r\nLocalCertificateDestinationPath\t=C:\\nginx\\\r\nPathToNginx.exe\t\t\t\t\t=C:\\nginx\\nginx.exe\r\n\r\nCertBotRenewalCommand\t\t\t=certbot certonly --authenticator standalone --csr /home/user/CertBot/domain.csr --agree-tos --no-eff-email --http-01-port 8080 --cert-path /home/user/CertBot/cert.crt --fullchain-path /home/user/CertBot/fullChain.crt --chain-path /home/user/CertBot/chain.crt --config-dir /home/user/CertBot/config --work-dir /home/user/CertBot/workingDirectory --logs-dir /home/user/CertBot/logs");
49+
Log.FastLog("Config not found, crating template: " + assemblyPath + "\\config.txt", LogSeverity.Alert, "LoadConfig");
50+
return false;
51+
}
52+
catch (Exception exception)
53+
{
54+
Log.FastLog("Config not found, unable to create template in: " + assemblyPath + "\n" + exception.Message, LogSeverity.Error, "LoadConfig");
55+
}
56+
57+
return false;
58+
}
59+
60+
String[] configLines = null;
61+
62+
try
63+
{
64+
configLines = File.ReadAllLines(assemblyPath + "\\config.txt");
65+
}
66+
catch (Exception exception)
67+
{
68+
Log.FastLog("Unable to read config: " + exception.Message, LogSeverity.Error, "LoadConfig");
69+
return false;
70+
}
71+
72+
Int32 configLinesLength = configLines!.Length;
73+
74+
if (configLinesLength < 7)
75+
{
76+
Log.FastLog("Invalid config file, found less than 7 lines", LogSeverity.Error, "LoadConfig");
77+
return false;
78+
}
79+
80+
ParseConfig(configLines, configLinesLength, ref configuration);
81+
82+
ValidateConfig(ref configuration);
83+
84+
return true;
85+
}
86+
87+
private static void ParseConfig(String[] configLines, Int32 configLinesLength, ref Configuration configuration)
88+
{
89+
for (Int32 i = 0; i < configLinesLength; ++i)
90+
{
91+
Match match;
92+
93+
if (configuration.CertBotIP == null && (match = Regex.Match(configLines[i], REGEX_CERTBOT_IP)).Success)
94+
{
95+
if (!IPAddress.TryParse(match.Groups[1].Value, out _))
96+
{
97+
Log.FastLog($"Invalid config value for 'CertBot-IP', value was: '{match.Groups[1].Value}', expected IPAddress", LogSeverity.Error, "ParseConfig");
98+
Environment.Exit(-1);
99+
}
100+
101+
configuration.CertBotIP = match.Groups[1].Value;
102+
continue;
103+
}
104+
105+
if (configuration.SSHUsername == null && (match = Regex.Match(configLines[i], REGEX_SSH_USERNAME)).Success)
106+
{
107+
configuration.SSHUsername = match.Groups[1].Value;
108+
continue;
109+
}
110+
111+
if (configuration.SSHPrivateKeyPath == null && (match = Regex.Match(configLines[i], REGEX_SSH_PKEY_PATH)).Success)
112+
{
113+
if (!File.Exists(match.Groups[1].Value))
114+
{
115+
Log.FastLog($"Invalid config value for 'SSH-PrivateKeyPath', value was: '{match.Groups[1].Value}', file not found", LogSeverity.Error, "ParseConfig");
116+
Environment.Exit(-1);
117+
}
118+
119+
configuration.SSHPrivateKeyPath = match.Groups[1].Value;
120+
continue;
121+
}
122+
123+
if (configuration.RemoteCertBotPath == null && (match = Regex.Match(configLines[i], REGEX_REMOTE_CERTBOT_PATH)).Success)
124+
{
125+
configuration.RemoteCertBotPath = match.Groups[1].Value;
126+
continue;
127+
}
128+
129+
if (configuration.LocalCertificateOutputPath == null && (match = Regex.Match(configLines[i], REGEX_LOCAL_CERT_OUT_PATH)).Success)
130+
{
131+
if (!Directory.Exists(match.Groups[1].Value))
132+
{
133+
Log.FastLog($"Invalid config value for 'LocalCertificateDestinationPath', value was: '{match.Groups[1].Value}', directory not found", LogSeverity.Error, "ParseConfig");
134+
Environment.Exit(-1);
135+
}
136+
137+
configuration.LocalCertificateOutputPath = match.Groups[1].Value;
138+
continue;
139+
}
140+
141+
if (configuration.NginxPath == null && (match = Regex.Match(configLines[i], REGEX_NGINX_EXE_PATH)).Success)
142+
{
143+
if (!File.Exists(match.Groups[1].Value))
144+
{
145+
Log.FastLog($"Invalid config value for 'PathToNginx.exe', value was: '{match.Groups[1].Value}', file not found", LogSeverity.Error, "ParseConfig");
146+
Environment.Exit(-1);
147+
}
148+
149+
configuration.NginxPath = match.Groups[1].Value;
150+
continue;
151+
}
152+
153+
if (configuration.RenewalCommand == null && (match = Regex.Match(configLines[i], REGEX_RENEWAL_COMMAND)).Success)
154+
{
155+
configuration.RenewalCommand = match.Groups[1].Value;
156+
continue;
157+
}
158+
}
159+
}
160+
161+
private static void ValidateConfig(ref Configuration configuration)
162+
{
163+
if (configuration.CertBotIP == null)
164+
{
165+
Log.FastLog("Invalid config file, 'CertBot-IP' not found", LogSeverity.Error, "ParseConfig");
166+
Environment.Exit(-1);
167+
}
168+
169+
if (configuration.SSHUsername == null)
170+
{
171+
Log.FastLog("Invalid config file, 'SSH-Username' not found", LogSeverity.Error, "ParseConfig");
172+
Environment.Exit(-1);
173+
}
174+
175+
if (configuration.SSHPrivateKeyPath == null)
176+
{
177+
Log.FastLog("Invalid config file, 'SSH-PrivateKeyPath' not found", LogSeverity.Error, "ParseConfig");
178+
Environment.Exit(-1);
179+
}
180+
181+
if (configuration.RemoteCertBotPath == null)
182+
{
183+
Log.FastLog("Invalid config file, 'RemoteCertBotDirectory' not found", LogSeverity.Error, "ParseConfig");
184+
Environment.Exit(-1);
185+
}
186+
187+
if (configuration.LocalCertificateOutputPath == null)
188+
{
189+
Log.FastLog("Invalid config file, 'LocalCertificateDestinationPath' not found", LogSeverity.Error, "ParseConfig");
190+
Environment.Exit(-1);
191+
}
192+
193+
if (configuration.NginxPath == null)
194+
{
195+
Log.FastLog("Invalid config file, 'PathToNginx.exe' not found", LogSeverity.Error, "ParseConfig");
196+
Environment.Exit(-1);
197+
}
198+
199+
if (configuration.RenewalCommand == null)
200+
{
201+
Log.FastLog("Invalid config file, 'CertBotRenewalCommand' not found", LogSeverity.Error, "ParseConfig");
202+
Environment.Exit(-1);
203+
}
204+
}
205+
}
206+
}

2. ConnectSftp.cs

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
using BSS.Logging;
2+
using Renci.SshNet;
3+
using System;
4+
5+
#pragma warning disable CS8625
6+
7+
namespace CertBotHelper
8+
{
9+
internal static partial class Program
10+
{
11+
private static Boolean ConnectSftp(ref Configuration configuration, out SftpClient sftpClient)
12+
{
13+
try
14+
{
15+
sftpClient = new(configuration.CertBotIP, configuration.SSHUsername, new PrivateKeyFile(configuration.SSHPrivateKeyPath));
16+
}
17+
catch (Exception exception)
18+
{
19+
Log.FastLog($"Unable to create new SftpClient, invalid private key?\n{exception.Message}", LogSeverity.Critical, "SftpClient");
20+
sftpClient = null;
21+
return false;
22+
}
23+
24+
try
25+
{
26+
sftpClient.Connect();
27+
Log.FastLog($"Connected to " + configuration.CertBotIP, LogSeverity.Info, "SftpClient");
28+
}
29+
catch (Exception exception)
30+
{
31+
Log.FastLog($"Unable to connect to {configuration.CertBotIP}\n{exception.Message}", LogSeverity.Critical, "SftpClient");
32+
return false;
33+
}
34+
35+
return true;
36+
}
37+
}
38+
}

3. PerformCertificateRenewal.cs

+112
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
using BSS.Logging;
2+
using Renci.SshNet;
3+
using System;
4+
5+
namespace CertBotHelper
6+
{
7+
internal static partial class Program
8+
{
9+
private static Boolean PerformCertificateRenewal(SftpClient sftpClient, ref Configuration configuration)
10+
{
11+
#region Prepare and Connect
12+
try
13+
{
14+
if (sftpClient.Exists(configuration.RemoteCertBotPath + "cert.crt"))
15+
{
16+
Log.FastLog("Found cert.crt in remote CertBot directory, removing.", LogSeverity.Info, "PreRenewal");
17+
sftpClient.DeleteFile(configuration.RemoteCertBotPath + "cert.crt");
18+
}
19+
20+
if (sftpClient.Exists(configuration.RemoteCertBotPath + "chain.crt"))
21+
{
22+
Log.FastLog("Found chain.crt in remote CertBot directory, removing.", LogSeverity.Info, "PreRenewal");
23+
sftpClient.DeleteFile(configuration.RemoteCertBotPath + "chain.crt");
24+
}
25+
26+
if (sftpClient.Exists(configuration.RemoteCertBotPath + "fullChain.crt"))
27+
{
28+
Log.FastLog("Found fullChain.crt in remote CertBot directory, removing.", LogSeverity.Info, "PreRenewal");
29+
sftpClient.DeleteFile(configuration.RemoteCertBotPath + "fullChain.crt");
30+
}
31+
}
32+
catch (Exception exception)
33+
{
34+
Log.FastLog($"An error occurred whilst preparing the remote certificate directory\n{exception.Message}", LogSeverity.Error, "PreCheck");
35+
return false;
36+
}
37+
38+
SshClient sshClient;
39+
40+
try
41+
{
42+
sshClient = new(configuration.CertBotIP, configuration.SSHUsername, new PrivateKeyFile(configuration.SSHPrivateKeyPath));
43+
}
44+
catch (Exception exception)
45+
{
46+
Log.FastLog($"Unable to create new SshClient, invalid private key?\n{exception.Message}", LogSeverity.Critical, "SshClient");
47+
return false;
48+
}
49+
50+
try
51+
{
52+
sshClient.Connect();
53+
Log.FastLog($"Connected to " + configuration.CertBotIP, LogSeverity.Info, "SshClient");
54+
}
55+
catch (Exception exception)
56+
{
57+
Log.FastLog($"Unable to connect to {configuration.CertBotIP}\n{exception.Message}", LogSeverity.Critical, "SshClient");
58+
return false;
59+
}
60+
#endregion
61+
62+
String stdOut;
63+
String errOut;
64+
65+
#region Run Command
66+
try
67+
{
68+
Log.FastLog("Attempting to run renewal command on machine", LogSeverity.Info, "CertRenewal");
69+
SshCommand sshCommand = sshClient.CreateCommand(configuration.RenewalCommand);
70+
stdOut = sshCommand.Execute();
71+
errOut = sshCommand.Error;
72+
73+
sshCommand.Dispose();
74+
sshClient.Disconnect();
75+
sshClient.Dispose();
76+
}
77+
catch (Exception exception)
78+
{
79+
Log.FastLog($"Failed to run renewal command on remote machine\n{exception.Message}", LogSeverity.Critical, "CertRenewal");
80+
return false;
81+
}
82+
#endregion
83+
84+
#region Validate after Command
85+
try
86+
{
87+
Boolean filesArePresent = true;
88+
89+
if (!sftpClient.Exists(configuration.RemoteCertBotPath + "cert.crt")) filesArePresent = false;
90+
if (!sftpClient.Exists(configuration.RemoteCertBotPath + "chain.crt")) filesArePresent = false;
91+
if (!sftpClient.Exists(configuration.RemoteCertBotPath + "fullChain.crt")) filesArePresent = false;
92+
93+
if (!filesArePresent)
94+
{
95+
Log.FastLog("Not all certificates were found! CertBot errOut output was:\n" + errOut, LogSeverity.Error, "PostRenewCheck");
96+
97+
return false;
98+
}
99+
100+
Log.FastLog("All certificates present on server after renewal, proceeding with download", LogSeverity.Info, "PostRenewCheck");
101+
}
102+
catch (Exception exception)
103+
{
104+
Log.FastLog($"An error occurred whilst checking if all certificates are present on the server\n{exception.Message}", LogSeverity.Error, "PostRenewCheck");
105+
return false;
106+
}
107+
#endregion
108+
109+
return true;
110+
}
111+
}
112+
}

0 commit comments

Comments
 (0)