summaryrefslogtreecommitdiffstats
path: root/win
diff options
context:
space:
mode:
authorsr55 <[email protected]>2020-04-11 13:00:41 +0100
committersr55 <[email protected]>2020-04-11 13:00:49 +0100
commita06bd83f2d1b1e9edc190fa09bdb7f0752783a7f (patch)
tree4e702f67080eb77e76879e75139414fb0637d4ab /win
parentc3d62f1465fc9813d079bdf33f2e062a48ec8549 (diff)
WinGui: Improvements to the Process Isolation Worker.
- Harden the worker process. Token is now required as a HTTP header for all actions. - Added an option to portable.ini to completely disable this functioanlity. May be useful for some enterprise environents - Few fixes
Diffstat (limited to 'win')
-rw-r--r--win/CS/HandBrake.Worker/HttpServer.cs46
-rw-r--r--win/CS/HandBrake.Worker/Program.cs8
-rw-r--r--win/CS/HandBrakeWPF/Converters/OptionTabConverter.cs5
-rw-r--r--win/CS/HandBrakeWPF/Instance/RemoteInstance.cs20
-rw-r--r--win/CS/HandBrakeWPF/Utilities/HttpRequestBase.cs54
-rw-r--r--win/CS/HandBrakeWPF/Utilities/Portable.cs16
-rw-r--r--win/CS/HandBrakeWPF/ViewModels/OptionsViewModel.cs8
-rw-r--r--win/CS/HandBrakeWPF/Views/OptionsView.xaml22
-rw-r--r--win/CS/HandBrakeWPF/portable.ini.template6
9 files changed, 146 insertions, 39 deletions
diff --git a/win/CS/HandBrake.Worker/HttpServer.cs b/win/CS/HandBrake.Worker/HttpServer.cs
index 3c9a36b37..ef8811ab6 100644
--- a/win/CS/HandBrake.Worker/HttpServer.cs
+++ b/win/CS/HandBrake.Worker/HttpServer.cs
@@ -19,16 +19,20 @@ namespace HandBrake.Worker
public class HttpServer
{
+ private readonly string uiToken;
+
private readonly HttpListener httpListener = new HttpListener();
private readonly Dictionary<string, Func<HttpListenerRequest, string>> apiHandlers;
- public HttpServer(Dictionary<string, Func<HttpListenerRequest, string>> apiCalls, int port)
+ public HttpServer(Dictionary<string, Func<HttpListenerRequest, string>> apiCalls, int port, string token)
{
if (!HttpListener.IsSupported)
{
throw new NotSupportedException("HttpListener not supported on this computer.");
}
+ this.uiToken = token;
+
// Store the Handlers
this.apiHandlers = new Dictionary<string, Func<HttpListenerRequest, string>>(apiCalls);
@@ -65,15 +69,30 @@ namespace HandBrake.Worker
try
{
string path = context.Request.RawUrl.TrimStart('/').TrimEnd('/');
+ string token = context.Request.Headers.Get("token");
+ if (!this.IsAuthenticated(token))
+ {
+ string rstr = "Worker: Access Denied. The token provided in the HTTP header was not valid.";
+ Console.WriteLine(rstr);
+ byte[] buf = Encoding.UTF8.GetBytes(rstr);
+ context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
+ context.Response.ContentLength64 = buf.Length;
+ context.Response.OutputStream.Write(buf, 0, buf.Length);
+ return;
+ }
+
Debug.WriteLine("Handling call to: " + path);
if (this.apiHandlers.TryGetValue(path, out var actionToPerform))
{
string rstr = actionToPerform(context.Request);
- byte[] buf = Encoding.UTF8.GetBytes(rstr);
- context.Response.ContentLength64 = buf.Length;
- context.Response.OutputStream.Write(buf, 0, buf.Length);
+ if (!string.IsNullOrEmpty(rstr))
+ {
+ byte[] buf = Encoding.UTF8.GetBytes(rstr);
+ context.Response.ContentLength64 = buf.Length;
+ context.Response.OutputStream.Write(buf, 0, buf.Length);
+ }
}
else
{
@@ -85,7 +104,7 @@ namespace HandBrake.Worker
}
catch (Exception exc)
{
- Debug.WriteLine(exc);
+ Console.WriteLine("Worker: Listener Thread: " + exc);
}
finally
{
@@ -97,7 +116,7 @@ namespace HandBrake.Worker
}
catch (Exception exc)
{
- Debug.WriteLine(exc);
+ Console.WriteLine("Worker: " + exc);
}
});
}
@@ -107,5 +126,20 @@ namespace HandBrake.Worker
this.httpListener.Stop();
this.httpListener.Close();
}
+
+ public bool IsAuthenticated(string token)
+ {
+ if (string.IsNullOrEmpty(token))
+ {
+ return false;
+ }
+
+ if (token != this.uiToken)
+ {
+ return false;
+ }
+
+ return true;
+ }
}
} \ No newline at end of file
diff --git a/win/CS/HandBrake.Worker/Program.cs b/win/CS/HandBrake.Worker/Program.cs
index f925ade38..a71192a41 100644
--- a/win/CS/HandBrake.Worker/Program.cs
+++ b/win/CS/HandBrake.Worker/Program.cs
@@ -25,6 +25,7 @@ namespace HandBrake.Worker
public static void Main(string[] args)
{
int port = 8037; // Default Port;
+ string token = null;
if (args.Length != 0)
{
@@ -38,6 +39,11 @@ namespace HandBrake.Worker
port = parsedPort;
}
}
+
+ if (argument.StartsWith("--token"))
+ {
+ token = argument.TrimStart("--token=".ToCharArray());
+ }
}
}
@@ -47,7 +53,7 @@ namespace HandBrake.Worker
Console.WriteLine("Worker: Starting Web Server on port {0} ...", port);
Dictionary<string, Func<HttpListenerRequest, string>> apiHandlers = RegisterApiHandlers();
- HttpServer webServer = new HttpServer(apiHandlers, port);
+ HttpServer webServer = new HttpServer(apiHandlers, port, token);
webServer.Run();
Console.WriteLine("Worker: Server Started");
diff --git a/win/CS/HandBrakeWPF/Converters/OptionTabConverter.cs b/win/CS/HandBrakeWPF/Converters/OptionTabConverter.cs
index 9ad7111ec..069918a71 100644
--- a/win/CS/HandBrakeWPF/Converters/OptionTabConverter.cs
+++ b/win/CS/HandBrakeWPF/Converters/OptionTabConverter.cs
@@ -22,11 +22,14 @@ namespace HandBrakeWPF.Converters
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
OptionsTab[] tabs = value as OptionsTab[];
- if (tabs != null && UwpDetect.IsUWP())
+ if (tabs != null && (UwpDetect.IsUWP() || !Portable.IsUpdateCheckEnabled()))
{
return tabs.Where(s => s != OptionsTab.Updates).ToArray();
}
+
+
+
return value;
}
diff --git a/win/CS/HandBrakeWPF/Instance/RemoteInstance.cs b/win/CS/HandBrakeWPF/Instance/RemoteInstance.cs
index 87af203c8..de0d50cc4 100644
--- a/win/CS/HandBrakeWPF/Instance/RemoteInstance.cs
+++ b/win/CS/HandBrakeWPF/Instance/RemoteInstance.cs
@@ -17,6 +17,7 @@ namespace HandBrakeWPF.Instance
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
+ using System.Text;
using System.Threading.Tasks;
using System.Timers;
using System.Windows.Media.Animation;
@@ -48,9 +49,7 @@ namespace HandBrakeWPF.Instance
public class RemoteInstance : HttpRequestBase, IEncodeInstance, IDisposable
{
private readonly HBConfiguration configuration;
-
private readonly ILog logService;
-
private readonly IUserSettingService userSettingService;
private const double EncodePollIntervalMs = 500;
@@ -94,7 +93,7 @@ namespace HandBrakeWPF.Instance
EnableHardwareAcceleration = true,
LogDirectory = DirectoryUtilities.GetLogDirectory(),
LogVerbosity = this.userSettingService.GetUserSetting<int>(UserSettingConstants.Verbosity)
- };
+ };
initCommand.LogFile = Path.Combine(initCommand.LogDirectory, string.Format("activity_log.worker.{0}.txt", GeneralUtilities.ProcessId));
@@ -134,7 +133,6 @@ namespace HandBrakeWPF.Instance
public void Dispose()
{
- this.client?.Dispose();
this.workerProcess?.Dispose();
}
@@ -142,12 +140,15 @@ namespace HandBrakeWPF.Instance
{
if (this.workerProcess == null || this.workerProcess.HasExited)
{
+ var plainTextBytes = Encoding.UTF8.GetBytes(Guid.NewGuid().ToString());
+ this.base64Token = Convert.ToBase64String(plainTextBytes);
+
workerProcess = new Process
{
StartInfo =
{
FileName = "HandBrake.Worker.exe",
- Arguments = string.Format(" --port={0}", port),
+ Arguments = string.Format(" --port={0} --token={1}", port, this.base64Token),
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
@@ -227,8 +228,6 @@ namespace HandBrakeWPF.Instance
}
response = await this.MakeHttpGetRequest("PollEncodeProgress");
-
- this.retryCount = 0; // Reset
}
catch (Exception e)
{
@@ -241,6 +240,8 @@ namespace HandBrakeWPF.Instance
return;
}
+ this.retryCount = 0; // Reset
+
string statusJson = response.JsonResponse;
JsonState state = JsonConvert.DeserializeObject<JsonState>(statusJson);
@@ -278,6 +279,11 @@ namespace HandBrakeWPF.Instance
private int GetOpenPort(int startPort)
{
+ if (startPort == 0)
+ {
+ startPort = 8037;
+ }
+
int portStartIndex = startPort;
IPGlobalProperties properties = IPGlobalProperties.GetIPGlobalProperties();
diff --git a/win/CS/HandBrakeWPF/Utilities/HttpRequestBase.cs b/win/CS/HandBrakeWPF/Utilities/HttpRequestBase.cs
index cc2898b43..fd23565e3 100644
--- a/win/CS/HandBrakeWPF/Utilities/HttpRequestBase.cs
+++ b/win/CS/HandBrakeWPF/Utilities/HttpRequestBase.cs
@@ -10,6 +10,7 @@
namespace HandBrakeWPF.Utilities
{
using System;
+ using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
@@ -20,11 +21,14 @@ namespace HandBrakeWPF.Utilities
public class HttpRequestBase
{
- protected readonly JsonSerializerSettings jsonNetSettings = new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore };
- protected HttpClient client = new HttpClient();
protected string serverUrl;
+
protected int port;
+ protected string base64Token;
+
+ private readonly JsonSerializerSettings jsonNetSettings = new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore };
+
public async Task<ServerResponse> MakeHttpJsonPostRequest(string urlPath, string json)
{
if (string.IsNullOrEmpty(json))
@@ -32,14 +36,26 @@ namespace HandBrakeWPF.Utilities
throw new InvalidOperationException("No Post Values Found.");
}
- StringContent content = new StringContent(json, Encoding.UTF8, "application/json");
- HttpResponseMessage response = await client.PostAsync(this.serverUrl + urlPath, content);
- if (response != null)
+ using (HttpClient client = new HttpClient())
{
- string returnContent = await response.Content.ReadAsStringAsync();
- ServerResponse serverResponse = new ServerResponse(response.IsSuccessStatusCode, returnContent);
+ HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Post, this.serverUrl + urlPath);
+ if (!string.IsNullOrEmpty(this.base64Token))
+ {
+ requestMessage.Headers.Add("token", this.base64Token);
+ }
+
+ requestMessage.Content = new StringContent(json, Encoding.UTF8, "application/json");
- return serverResponse;
+ using (HttpResponseMessage response = await client.SendAsync(requestMessage))
+ {
+ if (response != null)
+ {
+ string returnContent = await response.Content.ReadAsStringAsync();
+ ServerResponse serverResponse = new ServerResponse(response.IsSuccessStatusCode, returnContent);
+
+ return serverResponse;
+ }
+ }
}
return null;
@@ -47,13 +63,25 @@ namespace HandBrakeWPF.Utilities
public async Task<ServerResponse> MakeHttpGetRequest(string urlPath)
{
- HttpResponseMessage response = await client.GetAsync(this.serverUrl + urlPath);
- if (response != null)
+ using (HttpClient client = new HttpClient())
{
- string returnContent = await response.Content.ReadAsStringAsync();
- ServerResponse serverResponse = new ServerResponse(response.IsSuccessStatusCode, returnContent);
+ HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Get, this.serverUrl + urlPath);
+ if (!string.IsNullOrEmpty(this.base64Token))
+ {
+ requestMessage.Headers.Add("token", this.base64Token);
+ }
+
+ using (HttpResponseMessage response = await client.SendAsync(requestMessage))
+ {
+ if (response != null)
+ {
+ string returnContent = await response.Content.ReadAsStringAsync();
+ ServerResponse serverResponse = null;
+ serverResponse = response.StatusCode == HttpStatusCode.Unauthorized ? new ServerResponse(false, returnContent) : new ServerResponse(response.IsSuccessStatusCode, returnContent);
- return serverResponse;
+ return serverResponse;
+ }
+ }
}
return null;
diff --git a/win/CS/HandBrakeWPF/Utilities/Portable.cs b/win/CS/HandBrakeWPF/Utilities/Portable.cs
index ecde42d82..578c3fe76 100644
--- a/win/CS/HandBrakeWPF/Utilities/Portable.cs
+++ b/win/CS/HandBrakeWPF/Utilities/Portable.cs
@@ -193,6 +193,22 @@ namespace HandBrakeWPF.Utilities
return true; // Default to On.
}
+ public static bool IsRemoteWorkerProcessEnabled()
+ {
+ if (keyPairs.ContainsKey("remote.worker.enabled"))
+ {
+ string enabled = keyPairs["remote.worker.enabled"];
+ if (!string.IsNullOrEmpty(enabled) && enabled.Trim() == "true")
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ return true; // Default to On.
+ }
+
/// <summary>
/// The get temp directory.
/// </summary>
diff --git a/win/CS/HandBrakeWPF/ViewModels/OptionsViewModel.cs b/win/CS/HandBrakeWPF/ViewModels/OptionsViewModel.cs
index 6796141fd..0e92023dd 100644
--- a/win/CS/HandBrakeWPF/ViewModels/OptionsViewModel.cs
+++ b/win/CS/HandBrakeWPF/ViewModels/OptionsViewModel.cs
@@ -1354,6 +1354,14 @@ namespace HandBrakeWPF.ViewModels
}
}
+ public bool IsRemoteWorkedAllowed
+ {
+ get
+ {
+ return Portable.IsRemoteWorkerProcessEnabled();
+ }
+ }
+
#region Public Methods
/// <summary>
diff --git a/win/CS/HandBrakeWPF/Views/OptionsView.xaml b/win/CS/HandBrakeWPF/Views/OptionsView.xaml
index 0abb41364..606b940ac 100644
--- a/win/CS/HandBrakeWPF/Views/OptionsView.xaml
+++ b/win/CS/HandBrakeWPF/Views/OptionsView.xaml
@@ -113,7 +113,7 @@
<TextBlock Text="{x:Static Properties:Resources.Options_UserInterface}" FontSize="14" Margin="0,0,0,10"/>
<StackPanel Orientation="Horizontal" Margin="20,0,0,5">
- <TextBlock Text="{x:Static Properties:Resources.OptionsView_Language}" Margin="0,0,0,0" VerticalAlignment="Center"/>
+ <TextBlock Text="{x:Static Properties:Resources.OptionsView_Language}" Margin="0,0,0,0" VerticalAlignment="Center"/>
<ComboBox DisplayMemberPath="Name" ItemsSource="{Binding InterfaceLanguages}" SelectedItem="{Binding SelectedLanguage}" Margin="5,0,0,0" HorizontalAlignment="Left" Width="150" />
</StackPanel>
@@ -185,7 +185,7 @@
<Button Content="{x:Static Properties:Resources.Browse}" Margin="5,0,0,0" Grid.Column="2" Grid.Row="0" cal:Message.Attach="[Event Click] = [Action BrowseAutoNamePath]" HorizontalAlignment="Left" />
<TextBlock Text="{x:Static Properties:Resources.OptionsView_PathOptions}" Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="2" FontStyle="Italic" FontSize="11" TextWrapping="Wrap" />
<CheckBox IsChecked="{Binding AlwaysUseDefaultPath}" Content="{x:Static Properties:Resources.OptionsView_AlwaysUseDefaultPath}" ToolTip="{x:Static Properties:ResourcesTooltips.OptionsView_AlwaysUseDefaultPath}" Grid.Row="2" Grid.Column="1" />
-
+
<TextBlock VerticalAlignment="Center" Text="{x:Static Properties:Resources.Options_Format}" Grid.Column="0" Grid.Row="4" Margin="0,5,0,0" />
<TextBox Name="autoNameFormat" Text="{Binding AutonameFormat, UpdateSourceTrigger=PropertyChanged}" Width="380" Grid.Column="1" Grid.Row="4" Margin="0,0,0,0" ToolTip="{x:Static Properties:Resources.Options_AdditionalFormatOptions}" HorizontalAlignment="Left" />
@@ -249,7 +249,7 @@
<CheckBox Content="{x:Static Properties:Resources.Options_PromptBeforeAction}" VerticalAlignment="Center" Margin="0,5,0,0" Grid.Row="2" Grid.Column="1"
IsChecked="{Binding WhenDonePerformActionImmediately}" />
</Grid>
-
+
<TextBlock Text="{x:Static Properties:Resources.Options_EncodeCompleted}" FontSize="14" Margin="0,10,0,10" />
<StackPanel Orientation="Vertical" Margin="20,0,0,0">
@@ -389,7 +389,7 @@
<TextBlock Text="{x:Static Properties:Resources.Options_PriorityLevel}" Width="250" VerticalAlignment="Center" />
<ComboBox Name="processPriorityLevel" ItemsSource="{Binding PriorityLevelOptions, Converter={StaticResource ProcessPriorityConverter}}" SelectedItem="{Binding SelectedPriority, Converter={StaticResource ProcessPriorityConverter}}" Width="120" />
</StackPanel>
- </StackPanel>
+ </StackPanel>
</StackPanel>
<StackPanel Orientation="Vertical" Margin="0,10,0,10">
@@ -400,13 +400,17 @@
</StackPanel>
</StackPanel>
- <TextBlock Text="Worker Processes" FontSize="14" Margin="0,10,0,10"/>
+ <StackPanel Orientation="Vertical" Visibility="{Binding IsRemoteWorkedAllowed, Converter={StaticResource boolToVisConverter}}">
- <CheckBox Content="{x:Static Properties:Resources.OptionsView_EnableWorkerProcesses}" IsChecked="{Binding RemoteServiceEnabled}" Margin="10,5,0,0" />
+ <TextBlock Text="Worker Processes" FontSize="14" Margin="0,10,0,10"/>
+
+ <CheckBox Content="{x:Static Properties:Resources.OptionsView_EnableWorkerProcesses}" IsChecked="{Binding RemoteServiceEnabled}" Margin="10,5,0,0" />
+
+ <StackPanel Orientation="Horizontal" Margin="10,10,0,0">
+ <TextBlock Text="{x:Static Properties:Resources.OptionsView_WorkerDefaultPort}" />
+ <TextBox Text="{Binding RemoteServicePort}" Width="100" />
+ </StackPanel>
- <StackPanel Orientation="Horizontal" Margin="10,10,0,0">
- <TextBlock Text="{x:Static Properties:Resources.OptionsView_WorkerDefaultPort}" />
- <TextBox Text="{Binding RemoteServicePort}" Width="100" />
</StackPanel>
diff --git a/win/CS/HandBrakeWPF/portable.ini.template b/win/CS/HandBrakeWPF/portable.ini.template
index c667efece..21dae0bd5 100644
--- a/win/CS/HandBrakeWPF/portable.ini.template
+++ b/win/CS/HandBrakeWPF/portable.ini.template
@@ -7,7 +7,8 @@
# - tmp.dir => temporary files only. (i.e Preview images)
# - update.check => true | false (enabled / disabled, default disabled for portable)
# - hardware.enabled => true | false (Enables the hardware encoders such as QSV, NVENC or VCE)
-#
+# - remote.worker.enabled => true | false (Allows use of the remote worker process 'HandBrake.worker.exe' which uses a localhost http server. Setting to false will process jobs in-process.)
+#
# Set to 'cwd' to use the current applications directory. It will automatically create "storage" and "tmp" folders in this instance.
# Leave blank to use the system "TMP" directory and the "AppData" user profile folder.
#################################
@@ -15,4 +16,5 @@
storage.dir = cwd
tmp.dir = cwd
update.check = false
-hardware.enabled = true \ No newline at end of file
+hardware.enabled = true
+remote.worker.enabled = true \ No newline at end of file