diff --git a/NAPS2.Sdk.Tests/Config/ConfigScopeTests.cs b/NAPS2.Sdk.Tests/Config/ConfigScopeTests.cs
index 9bf55c9a3..a3e9fab41 100644
--- a/NAPS2.Sdk.Tests/Config/ConfigScopeTests.cs
+++ b/NAPS2.Sdk.Tests/Config/ConfigScopeTests.cs
@@ -33,7 +33,7 @@ namespace NAPS2.Sdk.Tests.Config
public void InternalDefaultsNotNullProps()
{
var config = InternalDefaults.GetCommonConfig();
- AssertPropNullOrNotNull(config, false);
+ AssertPropNullOrNotNull(config, false, "");
}
[Fact]
@@ -42,19 +42,19 @@ namespace NAPS2.Sdk.Tests.Config
var config = new CommonConfig();
Assert.NotNull(config.Version);
config.Version = null;
- AssertPropNullOrNotNull(config, true);
+ AssertPropNullOrNotNull(config, true, "");
}
- private static void AssertPropNullOrNotNull(object config, bool shouldBeNull)
+ private static void AssertPropNullOrNotNull(object config, bool shouldBeNull, string path)
{
- Assert.NotNull(config);
+ Assert.True(config != null, path);
foreach (var prop in config.GetType().GetProperties())
{
var value = prop.GetValue(config);
if (prop.CustomAttributes.Any(x => typeof(ChildAttribute).IsAssignableFrom(x.AttributeType)))
{
// Child, so recurse
- AssertPropNullOrNotNull(value, shouldBeNull);
+ AssertPropNullOrNotNull(value, shouldBeNull, $"{path}{prop.Name}.");
}
else
{
diff --git a/NAPS2.Sdk/Config/CommonConfig.cs b/NAPS2.Sdk/Config/CommonConfig.cs
index 34ccf6213..b645dea86 100644
--- a/NAPS2.Sdk/Config/CommonConfig.cs
+++ b/NAPS2.Sdk/Config/CommonConfig.cs
@@ -25,6 +25,7 @@ namespace NAPS2.Config
EmailSetup = new EmailSetup();
BatchSettings = new BatchSettings();
KeyboardShortcuts = new KeyboardShortcuts();
+ SslSetup = new SslSetup();
}
[Common]
@@ -176,6 +177,10 @@ namespace NAPS2.Config
[Child]
[Common]
public KeyboardShortcuts KeyboardShortcuts { get; set; }
+
+ [Child]
+ [Common]
+ public SslSetup SslSetup { get; set; }
[Common]
public ScanProfile DefaultProfileSettings { get; set; }
diff --git a/NAPS2.Sdk/Config/InternalDefaults.cs b/NAPS2.Sdk/Config/InternalDefaults.cs
index 20a300529..d0d5decb7 100644
--- a/NAPS2.Sdk/Config/InternalDefaults.cs
+++ b/NAPS2.Sdk/Config/InternalDefaults.cs
@@ -16,7 +16,6 @@ namespace NAPS2.Config
{
public static class InternalDefaults
{
- // TODO: Test that no properties are null
public static CommonConfig GetCommonConfig() =>
new CommonConfig
{
@@ -184,6 +183,11 @@ namespace NAPS2.Config
ZoomIn = "Ctrl+Oemplus",
ZoomOut = "Ctrl+OemMinus"
},
+ SslSetup = new SslSetup
+ {
+ WorkerCert = "",
+ WorkerPrivateKey = ""
+ },
DefaultProfileSettings = new ScanProfile { Version = ScanProfile.CURRENT_VERSION }
};
}
diff --git a/NAPS2.Sdk/Config/SslSetup.cs b/NAPS2.Sdk/Config/SslSetup.cs
new file mode 100644
index 000000000..881f90de0
--- /dev/null
+++ b/NAPS2.Sdk/Config/SslSetup.cs
@@ -0,0 +1,11 @@
+using NAPS2.Serialization;
+
+namespace NAPS2.Config
+{
+ public class SslSetup
+ {
+ public SecureString WorkerCert { get; set; }
+
+ public SecureString WorkerPrivateKey { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/NAPS2.Sdk/NAPS2.Sdk.csproj b/NAPS2.Sdk/NAPS2.Sdk.csproj
index d43b4a94e..df273bcf6 100644
--- a/NAPS2.Sdk/NAPS2.Sdk.csproj
+++ b/NAPS2.Sdk/NAPS2.Sdk.csproj
@@ -137,6 +137,7 @@
True
ClientCreds.resx
+
diff --git a/NAPS2.Sdk/Remoting/Worker/WorkerFactory.cs b/NAPS2.Sdk/Remoting/Worker/WorkerFactory.cs
index d3adb08bd..5e8cb7318 100644
--- a/NAPS2.Sdk/Remoting/Worker/WorkerFactory.cs
+++ b/NAPS2.Sdk/Remoting/Worker/WorkerFactory.cs
@@ -5,6 +5,7 @@ using System.IO;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
+using NAPS2.Config;
using NAPS2.Images.Storage;
using NAPS2.Platform;
using NAPS2.Util;
@@ -20,11 +21,12 @@ namespace NAPS2.Remoting.Worker
public static IWorkerFactory Default
{
- get => _default ?? (_default = new WorkerFactory(ImageContext.Default));
+ get => _default ??= new WorkerFactory(ImageContext.Default);
set => _default = value ?? throw new ArgumentNullException(nameof(value));
}
public const string WORKER_EXE_NAME = "NAPS2.Worker.exe";
+
public static readonly string[] SearchDirs =
{
Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location),
@@ -32,6 +34,8 @@ namespace NAPS2.Remoting.Worker
};
private readonly ImageContext imageContext;
+ private readonly ConfigProvider configProvider;
+ private readonly ConfigScopes configScopes;
private string workerExePath;
private BlockingCollection workerQueue;
@@ -41,6 +45,13 @@ namespace NAPS2.Remoting.Worker
this.imageContext = imageContext;
}
+ public WorkerFactory(ImageContext imageContext, ConfigProvider configProvider, ConfigScopes configScopes)
+ {
+ this.imageContext = imageContext;
+ this.configProvider = configProvider;
+ this.configScopes = configScopes;
+ }
+
private string WorkerExePath
{
get
@@ -90,7 +101,7 @@ namespace NAPS2.Remoting.Worker
}
}
- var (cert, privateKey) = SslHelper.GenerateRootCertificate();
+ var (cert, privateKey) = GetOrCreateCertAndPrivateKey();
WriteEncodedString(proc.StandardInput, cert);
WriteEncodedString(proc.StandardInput, privateKey);
var portStr = proc.StandardOutput.ReadLine();
@@ -103,6 +114,19 @@ namespace NAPS2.Remoting.Worker
return (proc, port, cert, privateKey);
}
+ private (string cert, string privateKey) GetOrCreateCertAndPrivateKey()
+ {
+ string cert = configProvider?.Get(c => c.SslSetup.WorkerCert);
+ string privateKey = configProvider?.Get(c => c.SslSetup.WorkerPrivateKey);
+ if (string.IsNullOrEmpty(cert) || string.IsNullOrEmpty(privateKey))
+ {
+ (cert, privateKey) = SslHelper.GenerateRootCertificate();
+ configScopes?.User.Set(c => c.SslSetup.WorkerCert = cert);
+ configScopes?.User.Set(c => c.SslSetup.WorkerPrivateKey = privateKey);
+ }
+ return (cert, privateKey);
+ }
+
private void WriteEncodedString(StreamWriter streamWriter, string value)
{
streamWriter.WriteLine(Convert.ToBase64String(Encoding.UTF8.GetBytes(value)));