Skip to content

Commit e4b9798

Browse files
authored
Add support for BitLocker (#1159)
1 parent 4a7d90e commit e4b9798

21 files changed

+550
-43
lines changed

Files.Launcher/Program.cs

Lines changed: 49 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -75,43 +75,6 @@ private static void UnhandledExceptionTrapper(object sender, UnhandledExceptionE
7575
Logger.Error(exception, exception.Message);
7676
}
7777

78-
private static bool HandleCommandLineArgs()
79-
{
80-
var localSettings = Windows.Storage.ApplicationData.Current.LocalSettings;
81-
var arguments = (string)localSettings.Values["Arguments"];
82-
if (!string.IsNullOrWhiteSpace(arguments))
83-
{
84-
localSettings.Values.Remove("Arguments");
85-
86-
if (arguments == "ShellCommand")
87-
{
88-
// Kill the process. This is a BRUTAL WAY to kill a process.
89-
#if DEBUG
90-
// In debug mode this kills this process too??
91-
#else
92-
var pid = (int)localSettings.Values["pid"];
93-
Process.GetProcessById(pid).Kill();
94-
#endif
95-
96-
Process process = new Process();
97-
process.StartInfo.UseShellExecute = true;
98-
process.StartInfo.FileName = "explorer.exe";
99-
process.StartInfo.CreateNoWindow = false;
100-
process.StartInfo.Arguments = (string)localSettings.Values["ShellCommand"];
101-
process.Start();
102-
103-
return true;
104-
}
105-
else if (arguments == "StartupTasks")
106-
{
107-
// Check QuickLook Availability
108-
QuickLook.CheckQuickLookAvailability(localSettings);
109-
return true;
110-
}
111-
}
112-
return false;
113-
}
114-
11578
private static async void Watcher_Changed(object sender, ShellItemChangeWatcher.ShellItemChangeEventArgs e)
11679
{
11780
Console.WriteLine($"File: {e.ChangedItems.FirstOrDefault()?.FileSystemPath} {e.ChangeType}");
@@ -198,8 +161,8 @@ private static async Task parseArguments(AppServiceRequestReceivedEventArgs args
198161
break;
199162

200163
case "RecycleBin":
201-
var action = (string)args.Request.Message["action"];
202-
await parseRecycleBinAction(args, action);
164+
var binAction = (string)args.Request.Message["action"];
165+
await parseRecycleBinAction(args, binAction);
203166
break;
204167

205168
case "StartupTasks":
@@ -242,6 +205,16 @@ private static async Task parseArguments(AppServiceRequestReceivedEventArgs args
242205
await args.Request.SendResponseAsync(responseArray);
243206
break;
244207

208+
case "Bitlocker":
209+
var bitlockerAction = (string)args.Request.Message["action"];
210+
if (bitlockerAction == "Unlock")
211+
{
212+
var drive = (string)args.Request.Message["drive"];
213+
var password = (string)args.Request.Message["password"];
214+
Win32API.UnlockBitlockerDrive(drive, password);
215+
await args.Request.SendResponseAsync(new ValueSet() { { "Bitlocker", "Unlock" } });
216+
}
217+
break;
245218
default:
246219
if (args.Request.Message.ContainsKey("Application"))
247220
{
@@ -414,6 +387,43 @@ private static void HandleApplicationLaunch(string application, AppServiceReques
414387
}
415388
}
416389

390+
private static bool HandleCommandLineArgs()
391+
{
392+
var localSettings = Windows.Storage.ApplicationData.Current.LocalSettings;
393+
var arguments = (string)localSettings.Values["Arguments"];
394+
if (!string.IsNullOrWhiteSpace(arguments))
395+
{
396+
localSettings.Values.Remove("Arguments");
397+
398+
if (arguments == "ShellCommand")
399+
{
400+
// Kill the process. This is a BRUTAL WAY to kill a process.
401+
#if DEBUG
402+
// In debug mode this kills this process too??
403+
#else
404+
var pid = (int)localSettings.Values["pid"];
405+
Process.GetProcessById(pid).Kill();
406+
#endif
407+
408+
Process process = new Process();
409+
process.StartInfo.UseShellExecute = true;
410+
process.StartInfo.FileName = "explorer.exe";
411+
process.StartInfo.CreateNoWindow = false;
412+
process.StartInfo.Arguments = (string)localSettings.Values["ShellCommand"];
413+
process.Start();
414+
415+
return true;
416+
}
417+
else if (arguments == "StartupTasks")
418+
{
419+
// Check QuickLook Availability
420+
QuickLook.CheckQuickLookAvailability(localSettings);
421+
return true;
422+
}
423+
}
424+
return false;
425+
}
426+
417427
private static void Connection_ServiceClosed(AppServiceConnection sender, AppServiceClosedEventArgs args)
418428
{
419429
// Signal the event so the process can shut down

Files.Launcher/Win32API.cs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.ComponentModel;
4+
using System.Diagnostics;
5+
using System.Drawing;
36
using System.Linq;
47
using System.Runtime.InteropServices;
58
using System.Text;
@@ -135,5 +138,25 @@ public static string[] CommandLineToArgs(string commandLine)
135138
Marshal.FreeHGlobal(argv);
136139
}
137140
}
141+
142+
public static void UnlockBitlockerDrive(string drive, string password)
143+
{
144+
try
145+
{
146+
Process process = new Process();
147+
process.StartInfo.UseShellExecute = true;
148+
process.StartInfo.Verb = "runas";
149+
process.StartInfo.FileName = "powershell.exe";
150+
process.StartInfo.CreateNoWindow = true;
151+
process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
152+
process.StartInfo.Arguments = $"-command \"$SecureString = ConvertTo-SecureString '{password}' -AsPlainText -Force; Unlock-BitLocker -MountPoint '{drive}' -Password $SecureString\"";
153+
process.Start();
154+
process.WaitForExit(30 * 1000);
155+
}
156+
catch (Win32Exception)
157+
{
158+
// If user cancels UAC
159+
}
160+
}
138161
}
139162
}

Files/Dialogs/BitlockerDialog.xaml

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<ContentDialog
2+
x:Class="Files.Dialogs.BitlockerDialog"
3+
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
4+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
5+
xmlns:local2="using:Files.Helpers"
6+
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
7+
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
8+
mc:Ignorable="d"
9+
CornerRadius="4"
10+
DefaultButton="None"
11+
Title="Enter password to unlock the drive"
12+
BorderThickness="0"
13+
PrimaryButtonClick="BitlockerDialog_PrimaryButtonClick"
14+
x:Name="BitlockerDriveDialog"
15+
PrimaryButtonText="Unlock"
16+
SecondaryButtonText="Cancel"
17+
x:Uid="BitlockerDialog"
18+
RequestedTheme="{x:Bind local2:ThemeHelper.RootTheme}">
19+
20+
<ContentDialog.PrimaryButtonStyle>
21+
<Style TargetType="Button" BasedOn="{StaticResource AccentButtonStyle}">
22+
<Setter Property="ContentTemplate">
23+
<Setter.Value>
24+
<DataTemplate x:DataType="Button">
25+
<StackPanel Spacing="5" Orientation="Horizontal">
26+
<FontIcon FontSize="14" Glyph="&#xEA18;" />
27+
<TextBlock Text="{Binding PrimaryButtonText, ElementName=BitlockerDriveDialog}" />
28+
</StackPanel>
29+
</DataTemplate>
30+
</Setter.Value>
31+
</Setter>
32+
</Style>
33+
</ContentDialog.PrimaryButtonStyle>
34+
35+
<Grid MinWidth="300">
36+
<StackPanel
37+
Orientation="Vertical"
38+
Spacing="4">
39+
<PasswordBox
40+
x:Name="PasswordInput"
41+
x:Uid="BitlockerDialogInputText"
42+
PlaceholderText="Password"
43+
Height="35"
44+
IsPasswordRevealButtonEnabled="True"
45+
PasswordRevealMode="Peek"
46+
PasswordChanged="BitlockerInput_TextChanged" />
47+
</StackPanel>
48+
</Grid>
49+
</ContentDialog>

Files/Dialogs/BitlockerDialog.xaml.cs

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
using System;
2+
using System.Threading.Tasks;
3+
using Windows.Foundation;
4+
using Windows.System;
5+
using Windows.UI.Xaml.Controls;
6+
7+
// The Content Dialog item template is documented at https://go.microsoft.com/fwlink/?LinkId=234238
8+
9+
namespace Files.Dialogs
10+
{
11+
public sealed partial class BitlockerDialog : ContentDialog
12+
{
13+
public PasswordBox inputBox;
14+
public string storedPasswordInput;
15+
16+
public BitlockerDialog(string drive)
17+
{
18+
this.InitializeComponent();
19+
inputBox = PasswordInput;
20+
IsPrimaryButtonEnabled = false;
21+
}
22+
23+
private void BitlockerDialog_PrimaryButtonClick(ContentDialog sender, ContentDialogButtonClickEventArgs args)
24+
{
25+
storedPasswordInput = inputBox.Password;
26+
}
27+
28+
private void BitlockerInput_TextChanged(object sender, Windows.UI.Xaml.RoutedEventArgs e)
29+
{
30+
var textBox = sender as PasswordBox;
31+
32+
if (string.IsNullOrEmpty(textBox.Password))
33+
{
34+
IsPrimaryButtonEnabled = false;
35+
}
36+
else
37+
{
38+
IsPrimaryButtonEnabled = true;
39+
}
40+
}
41+
42+
public new IAsyncOperation<ContentDialogResult> ShowAsync()
43+
{
44+
var tcs = new TaskCompletionSource<ContentDialogResult>();
45+
46+
this.PreviewKeyDown += (sender, e) =>
47+
{
48+
if (e.Key.Equals(VirtualKey.Enter))
49+
{
50+
var element = Windows.UI.Xaml.Input.FocusManager.GetFocusedElement(XamlRoot) as Button;
51+
if (element == null || element.Name == "PrimaryButton")
52+
{
53+
if (!IsPrimaryButtonEnabled) return;
54+
BitlockerDialog_PrimaryButtonClick(null, null);
55+
tcs.TrySetResult(ContentDialogResult.Primary);
56+
Hide();
57+
e.Handled = true;
58+
}
59+
else if (element != null && element.Name == "SecondaryButton")
60+
{
61+
tcs.TrySetResult(ContentDialogResult.Secondary);
62+
Hide();
63+
e.Handled = true;
64+
}
65+
}
66+
else if (e.Key.Equals(VirtualKey.Escape))
67+
{
68+
Hide();
69+
e.Handled = true;
70+
}
71+
};
72+
73+
var asyncOperation = base.ShowAsync();
74+
asyncOperation.AsTask().ContinueWith(task => tcs.TrySetResult(task.Result));
75+
return tcs.Task.AsAsyncOperation();
76+
}
77+
}
78+
}

Files/Files.csproj

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,9 @@
156156
<Compile Include="CommandLine\ParsedCommandType.cs" />
157157
<Compile Include="Converters\StorageDeleteOptionToBooleanConverter.cs" />
158158
<Compile Include="DataModels\SidebarPinnedModel.cs" />
159+
<Compile Include="Dialogs\BitlockerDialog.xaml.cs">
160+
<DependentUpon>BitlockerDialog.xaml</DependentUpon>
161+
</Compile>
159162
<Compile Include="Dialogs\ConfirmDeleteDialog.xaml.cs">
160163
<DependentUpon>ConfirmDeleteDialog.xaml</DependentUpon>
161164
</Compile>
@@ -377,6 +380,10 @@
377380
<Generator>MSBuild:Compile</Generator>
378381
<SubType>Designer</SubType>
379382
</ApplicationDefinition>
383+
<Page Include="Dialogs\BitlockerDialog.xaml">
384+
<Generator>MSBuild:Compile</Generator>
385+
<SubType>Designer</SubType>
386+
</Page>
380387
<Page Include="Dialogs\ConfirmDeleteDialog.xaml">
381388
<Generator>MSBuild:Compile</Generator>
382389
<SubType>Designer</SubType>

Files/MultilingualResources/Files.de-DE.xlf

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -861,6 +861,30 @@
861861
<source>Learn more about date formats</source>
862862
<target state="new">Learn more about date formats</target>
863863
</trans-unit>
864+
<trans-unit id="BitlockerDialog.PrimaryButtonText" translate="yes" xml:space="preserve">
865+
<source>Unlock</source>
866+
<target state="new">Unlock</target>
867+
</trans-unit>
868+
<trans-unit id="BitlockerDialog.SecondaryButtonText" translate="yes" xml:space="preserve">
869+
<source>Cancel</source>
870+
<target state="new">Cancel</target>
871+
</trans-unit>
872+
<trans-unit id="BitlockerDialog.Title" translate="yes" xml:space="preserve">
873+
<source>Enter password to unlock the drive</source>
874+
<target state="new">Enter password to unlock the drive</target>
875+
</trans-unit>
876+
<trans-unit id="BitlockerDialogInputText.PlaceholderText" translate="yes" xml:space="preserve">
877+
<source>Password</source>
878+
<target state="new">Password</target>
879+
</trans-unit>
880+
<trans-unit id="BitlockerInvalidPwDialog.Text" translate="yes" xml:space="preserve">
881+
<source>Please check the password and try again.</source>
882+
<target state="new">Please check the password and try again.</target>
883+
</trans-unit>
884+
<trans-unit id="BitlockerInvalidPwDialog.Title" translate="yes" xml:space="preserve">
885+
<source>BitLocker error</source>
886+
<target state="new">BitLocker error</target>
887+
</trans-unit>
864888
<trans-unit id="PropertiesFilesAndFoldersCount.Text" translate="yes" xml:space="preserve">
865889
<source>Contains:</source>
866890
<target state="new">Contains:</target>

Files/MultilingualResources/Files.es-ES.xlf

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -854,6 +854,30 @@
854854
<source>Learn more about date formats</source>
855855
<target state="translated">Mas información acerca de formatos de fecha</target>
856856
</trans-unit>
857+
<trans-unit id="BitlockerDialog.PrimaryButtonText" translate="yes" xml:space="preserve">
858+
<source>Unlock</source>
859+
<target state="new">Unlock</target>
860+
</trans-unit>
861+
<trans-unit id="BitlockerDialog.SecondaryButtonText" translate="yes" xml:space="preserve">
862+
<source>Cancel</source>
863+
<target state="new">Cancel</target>
864+
</trans-unit>
865+
<trans-unit id="BitlockerDialog.Title" translate="yes" xml:space="preserve">
866+
<source>Enter password to unlock the drive</source>
867+
<target state="new">Enter password to unlock the drive</target>
868+
</trans-unit>
869+
<trans-unit id="BitlockerDialogInputText.PlaceholderText" translate="yes" xml:space="preserve">
870+
<source>Password</source>
871+
<target state="new">Password</target>
872+
</trans-unit>
873+
<trans-unit id="BitlockerInvalidPwDialog.Text" translate="yes" xml:space="preserve">
874+
<source>Please check the password and try again.</source>
875+
<target state="new">Please check the password and try again.</target>
876+
</trans-unit>
877+
<trans-unit id="BitlockerInvalidPwDialog.Title" translate="yes" xml:space="preserve">
878+
<source>BitLocker error</source>
879+
<target state="new">BitLocker error</target>
880+
</trans-unit>
857881
<trans-unit id="PropertiesFilesAndFoldersCount.Text" translate="yes" xml:space="preserve">
858882
<source>Contains:</source>
859883
<target state="new">Contains:</target>

Files/MultilingualResources/Files.fr-FR.xlf

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -857,6 +857,30 @@
857857
<source>Learn more about date formats</source>
858858
<target state="new">Learn more about date formats</target>
859859
</trans-unit>
860+
<trans-unit id="BitlockerDialog.PrimaryButtonText" translate="yes" xml:space="preserve">
861+
<source>Unlock</source>
862+
<target state="new">Unlock</target>
863+
</trans-unit>
864+
<trans-unit id="BitlockerDialog.SecondaryButtonText" translate="yes" xml:space="preserve">
865+
<source>Cancel</source>
866+
<target state="new">Cancel</target>
867+
</trans-unit>
868+
<trans-unit id="BitlockerDialog.Title" translate="yes" xml:space="preserve">
869+
<source>Enter password to unlock the drive</source>
870+
<target state="new">Enter password to unlock the drive</target>
871+
</trans-unit>
872+
<trans-unit id="BitlockerDialogInputText.PlaceholderText" translate="yes" xml:space="preserve">
873+
<source>Password</source>
874+
<target state="new">Password</target>
875+
</trans-unit>
876+
<trans-unit id="BitlockerInvalidPwDialog.Text" translate="yes" xml:space="preserve">
877+
<source>Please check the password and try again.</source>
878+
<target state="new">Please check the password and try again.</target>
879+
</trans-unit>
880+
<trans-unit id="BitlockerInvalidPwDialog.Title" translate="yes" xml:space="preserve">
881+
<source>BitLocker error</source>
882+
<target state="new">BitLocker error</target>
883+
</trans-unit>
860884
<trans-unit id="PropertiesFilesAndFoldersCount.Text" translate="yes" xml:space="preserve">
861885
<source>Contains:</source>
862886
<target state="new">Contains:</target>

0 commit comments

Comments
 (0)