Skip to content

Commit

Permalink
Improved dialog for import/extract of certificates to support both sc…
Browse files Browse the repository at this point in the history
…enarios and command line + added cmd line extract-cert to msixherocli.exe + showing thumbprint in the dialog.
  • Loading branch information
marcinotorowski committed Dec 14, 2020
1 parent 280a2d6 commit 4dfcd7b
Show file tree
Hide file tree
Showing 11 changed files with 363 additions and 144 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ public CertificateViewModel(PersonalCertificate personalCertificate)
public string Subject => this.personalCertificate.Subject;

public string DigestAlgorithm => this.personalCertificate.DigestAlgorithm;

public string Thumbprint => this.personalCertificate.Thumbprint;

public CertificateStoreType StoreType => this.personalCertificate.StoreType;

Expand Down
19 changes: 2 additions & 17 deletions src/Otor.MsixHero.App/Modules/Dashboard/Views/DashboardView.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -152,21 +152,6 @@
Style="{StaticResource ButtonDescription}" Text="Create a new certificate for test and demo purposes" />
</StackPanel>
</Button>
<Button
IsEnabled="False">
<StackPanel>
<Path
Style="{StaticResource LargeIcon}"
Data="{StaticResource VectorImport}"
Margin="0 0 0 8" />
<TextBlock
controls:Highlighter.Selection="{Binding SearchKey}"
Style="{StaticResource ButtonLabel}" FontSize="14" Text="Install certificate" />
<TextBlock
controls:Highlighter.Selection="{Binding SearchKey}"
Style="{StaticResource ButtonDescription}" Text="Install certificate or import it from a package" />
</StackPanel>
</Button>
<Button
Command="{Binding ShowExtractCertificateDialog}">
<StackPanel>
Expand All @@ -176,10 +161,10 @@
Margin="0 0 0 8" />
<TextBlock
controls:Highlighter.Selection="{Binding SearchKey}"
Style="{StaticResource ButtonLabel}" FontSize="14" Text="Extract certificate" />
Style="{StaticResource ButtonLabel}" FontSize="14" Text="Extract or install certificate" />
<TextBlock
controls:Highlighter.Selection="{Binding SearchKey}"
Style="{StaticResource ButtonDescription}" Text="Extract a certificate from already signed package" />
Style="{StaticResource ButtonDescription}" Text="Install certificates or extract them from signed package" />
</StackPanel>
</Button>
</WrapPanel>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
<UserControl x:Class="Otor.MsixHero.App.Modules.Dialogs.Signing.CertificateExport.View.CertificateExportControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:controls="clr-namespace:Otor.MsixHero.App.Controls"
xmlns:viewModel="clr-namespace:Otor.MsixHero.App.Modules.Dialogs.Signing.CertificateExport.ViewModel"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance viewModel:CertificateExportViewModel}"
d:DesignHeight="450" d:DesignWidth="800">
<ScrollViewer Margin="0 16 0 0" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled">
<AdornerDecorator>
<StackPanel>
<TextBlock
Style="{StaticResource LabelTextBlock}"
controls:RequiredAdorner.IsRequired="True"
Text="Signed MSIX package or a certificate file" />
<DockPanel>
<Button TabIndex="5" Padding="10 0" Content="..." DockPanel.Dock="Right" Command="{Binding InputPath.Browse}" Margin="4 0 0 0" />
<TextBox x:Name="PathInput" TabIndex="4" Text="{Binding InputPath.CurrentValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True, ValidatesOnNotifyDataErrors=True, NotifyOnValidationError=True}" IsReadOnly="True" />
</DockPanel>

<Border
Visibility="{Binding CertificateDetails.HasValue, Converter={StaticResource BooleanToVisibilityConverter}}"
Background="#E8FFDD" Margin="0 16 0 0">
<Border.Style>
<Style TargetType="Border">
<Setter Property="LayoutTransform">
<Setter.Value>
<ScaleTransform ScaleY="0" />
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="Visibility" Value="Visible">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation From="0" To="1" Storyboard.TargetProperty="LayoutTransform.ScaleY" Duration="00:00:0.4" AccelerationRatio="0.5" DecelerationRatio="0.5" />
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="Opacity">
<SplineDoubleKeyFrame Value="0" KeyTime="00:00:00" />
<SplineDoubleKeyFrame Value="0" KeyTime="00:00:0.5" />
<SplineDoubleKeyFrame Value="1.0" KeyTime="00:00:1.0" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation From="1" To="0" Storyboard.TargetProperty="Opacity" Duration="00:00:0.4" AccelerationRatio="0.5" DecelerationRatio="0.5" />
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="LayoutTransform.ScaleY">
<SplineDoubleKeyFrame Value="1.0" KeyTime="00:00:00" />
<SplineDoubleKeyFrame Value="1.0" KeyTime="00:00:0.5" />
<SplineDoubleKeyFrame Value="0.0" KeyTime="00:00:1.0" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
</Style.Triggers>
</Style>
</Border.Style>
<StackPanel Margin="12">
<Label
Style="{StaticResource FormLabelThin}"
Content="Digital signature details:"
Margin="0 0 0 6" />
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>

<TextBlock Grid.Column="0" Grid.Row="0" Margin="0 4" Style="{StaticResource DataHeader}" Text="Issued for" />
<TextBlock Grid.Column="0" Grid.Row="1" Margin="0 4" Style="{StaticResource DataHeader}" Text="Issuer" />
<TextBlock Grid.Column="0" Grid.Row="2" Margin="0 4" Style="{StaticResource DataHeader}" Text="Digest algorithm" />
<TextBlock Grid.Column="0" Grid.Row="3" Margin="0 4" Style="{StaticResource DataHeader}" Text="Thumbprint" />

<TextBlock Grid.Column="1" Grid.Row="0" Margin="16 4 0 4" Style="{StaticResource DataValue}" Text="{Binding CertificateDetails.CurrentValue.DisplayName, FallbackValue='n/a', TargetNullValue='n/a'}" TextWrapping="Wrap" ToolTip="{Binding CertificateDetails.CurrentValue.Subject}" />
<TextBlock Grid.Column="1" Grid.Row="1" Margin="16 4 0 4" Style="{StaticResource DataValue}" Text="{Binding CertificateDetails.CurrentValue.Issuer, FallbackValue='n/a', TargetNullValue='n/a'}" TextWrapping="Wrap" />
<TextBlock Grid.Column="1" Grid.Row="2" Margin="16 4 0 4" Style="{StaticResource DataValue}" Text="{Binding CertificateDetails.CurrentValue.DigestAlgorithm, FallbackValue='n/a', TargetNullValue='n/a'}" TextWrapping="Wrap" />
<TextBlock Grid.Column="1" Grid.Row="3" Margin="16 4 0 4" Style="{StaticResource DataValue}" Text="{Binding CertificateDetails.CurrentValue.Thumbprint, FallbackValue='n/a', TargetNullValue='n/a'}" TextWrapping="Wrap" />
</Grid>
</StackPanel>
</Border>

<RadioButton
x:Name="RadioSave"
IsChecked="{Binding OperationType.CurrentValue, ConverterParameter={x:Static viewModel:CertOperationType.Extract}, Converter={StaticResource EnumToBooleanConverter}}"
GroupName="radio1"
Visibility="{Binding CanExtract.CurrentValue, Converter={StaticResource BooleanToVisibilityConverter}}"
Content="Save as .CER file"
Margin="0 16 0 6" />

<DockPanel
Visibility="{Binding CanExtract.CurrentValue, Converter={StaticResource BooleanToVisibilityConverter}}"
IsEnabled="{Binding ElementName=RadioSave, Path=IsChecked}"
Margin="22 0 0 6">
<Button TabIndex="5" Padding="10 0" Content="..." DockPanel.Dock="Right" Command="{Binding ExtractCertificate.Browse}"
Margin="4 0 0 0" />
<TextBox x:Name="PathOutput" TabIndex="4" Text="{Binding ExtractCertificate.CurrentValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True, ValidatesOnNotifyDataErrors=True, NotifyOnValidationError=True}" IsReadOnly="True" />
</DockPanel>

<RadioButton
Visibility="{Binding CanExtract.CurrentValue, Converter={StaticResource BooleanToVisibilityConverter}}"
IsChecked="{Binding OperationType.CurrentValue, ConverterParameter={x:Static viewModel:CertOperationType.Import}, Converter={StaticResource EnumToBooleanConverter}}"
GroupName="radio2"
Content="Import to Trusted People store" Margin="0 10 0 6" />
<TextBlock
Visibility="{Binding CanExtract.CurrentValue, Converter={StaticResource BooleanToVisibilityConverter}}"
Margin="22 0 0 0"
Style="{StaticResource DataHeader}"
TextWrapping="Wrap"
Text="After importing to the Trusted People store, all apps signed with this certificate will be trusted on this machine." />

<Border Visibility="{Binding CertificateDetails.HasValue, Converter={StaticResource BooleanToVisibilityConverter}}">
<TextBlock
Visibility="{Binding CanExtract.CurrentValue, Converter={StaticResource NegativeBooleanToVisibilityConverter}}"
Margin="0 16 0 0" Style="{StaticResource DataHeader}" TextWrapping="Wrap">
<Run Text="Press" />
<Run Text="Import certificate" FontWeight="SemiBold" />
<Run Text="to import the certificate." />
<Run Text="After importing to the Trusted People store, all apps signed with this certificate will be trusted on this machine." />
</TextBlock>
</Border>
</StackPanel>
</AdornerDecorator>
</ScrollViewer>
</UserControl>
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace Otor.MsixHero.App.Modules.Dialogs.Signing.CertificateExport.View
{
/// <summary>
/// Interaction logic for CertificateExportControl.xaml
/// </summary>
public partial class CertificateExportControl : UserControl
{
public CertificateExportControl()
{
InitializeComponent();
}
}
}
Loading

0 comments on commit 4dfcd7b

Please sign in to comment.