From 46f9f95dcf0153023dbf6af33cc8631a23471f70 Mon Sep 17 00:00:00 2001 From: MrSphay Date: Sat, 16 May 2026 13:05:12 +0200 Subject: [PATCH] Add diagnostics tab and UI animations --- .gitea/workflows/build.yml | 2 +- CHANGELOG.md | 7 + README.md | 4 +- scripts/Start-MrTrustGui.ps1 | 521 +++++++++++++++++++++++------------ 4 files changed, 362 insertions(+), 172 deletions(-) diff --git a/.gitea/workflows/build.yml b/.gitea/workflows/build.yml index 7405d2f..9382c32 100644 --- a/.gitea/workflows/build.yml +++ b/.gitea/workflows/build.yml @@ -11,7 +11,7 @@ jobs: build: runs-on: ubuntu-latest env: - MRTRUST_VERSION: 0.1.3 + MRTRUST_VERSION: 0.1.4 steps: - name: Checkout diff --git a/CHANGELOG.md b/CHANGELOG.md index 6572a20..ff9bbab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## 0.1.4 + +- Added a diagnostics tab for checking `.exe`, `.msi`, `.dll`, and `.cat` files. +- Added signature status, MrSphay signer matching, and Mark-of-the-Web detection. +- Added an in-app SmartScreen explanation to clarify reputation versus local certificate trust. +- Added subtle Modrinth-style hover, press, progress, and accent animations. + ## 0.1.3 - Added Ubuntu-runner signing support through `osslsigncode` and PFX secrets. diff --git a/README.md b/README.md index 96f8fab..5f24f31 100644 --- a/README.md +++ b/README.md @@ -126,7 +126,7 @@ Create or refresh local certificates: Build a release ZIP locally: ```powershell -.\scripts\New-MrTrustRelease.ps1 -Version 0.1.3 +.\scripts\New-MrTrustRelease.ps1 -Version 0.1.4 ``` Sign an artifact locally on Windows: @@ -219,7 +219,7 @@ The Gitea workflow builds `MrTrust.exe` on `ubuntu-latest` with .NET Windows cro On pushes to `main`, it: 1. builds the standalone Windows executable -2. packages `MrTrust-0.1.3.zip` +2. packages `MrTrust-0.1.4.zip` 3. uploads the workflow artifact 4. attaches the ZIP to the Gitea release diff --git a/scripts/Start-MrTrustGui.ps1 b/scripts/Start-MrTrustGui.ps1 index 8416682..685e932 100644 --- a/scripts/Start-MrTrustGui.ps1 +++ b/scripts/Start-MrTrustGui.ps1 @@ -10,6 +10,21 @@ $script:RootPath = Split-Path -Parent (Split-Path -Parent $MyInvocation.MyComman $script:RootCertificatePath = Join-Path $script:RootPath "assets\certificates\MrSphay-LocalTrust-Root.cer" $script:PublisherCertificatePath = Join-Path $script:RootPath "assets\certificates\MrSphay-CodeSigning.cer" $script:IconPath = Join-Path $script:RootPath "assets\MrTrust.ico" +$script:SelectedFilePath = $null +$script:CurrentAccent = 0 + +$colors = @{ + Background = [Drawing.Color]::FromArgb(18, 23, 26) + Panel = [Drawing.Color]::FromArgb(27, 33, 36) + PanelAlt = [Drawing.Color]::FromArgb(35, 43, 47) + Border = [Drawing.Color]::FromArgb(61, 73, 79) + Text = [Drawing.Color]::FromArgb(234, 239, 236) + Muted = [Drawing.Color]::FromArgb(165, 180, 172) + Green = [Drawing.Color]::FromArgb(28, 185, 111) + GreenHover = [Drawing.Color]::FromArgb(38, 205, 130) + Orange = [Drawing.Color]::FromArgb(242, 153, 74) + Red = [Drawing.Color]::FromArgb(235, 87, 87) +} function Test-IsAdministrator { $identity = [Security.Principal.WindowsIdentity]::GetCurrent() @@ -28,12 +43,7 @@ function Get-MrTrustCertificate { } function Get-TrustScope { - if ($script:AllUsersCheckBox.Checked) { - "LocalMachine" - } - else { - "CurrentUser" - } + if ($script:AllUsersCheckBox.Checked) { "LocalMachine" } else { "CurrentUser" } } function Get-StorePath { @@ -56,14 +66,67 @@ function Test-CertificateInstalled { @(Get-ChildItem -Path $storePath | Where-Object Thumbprint -eq $Certificate.Thumbprint).Count -gt 0 } -function Set-StatusText { - param([Parameter(Mandatory)][string]$Text) +function Set-Busy { + param([bool]$Busy) - $script:StatusLabel.Text = $Text + $script:ProgressBar.Visible = $Busy + if ($Busy) { + $script:ProgressBar.Style = "Marquee" + } } -function Refresh-MrTrustStatus { +function Set-StatusText { + param( + [Parameter(Mandatory)][string]$Text, + [Parameter(Mandatory)][Drawing.Color]$Color + ) + + $script:StatusLabel.Text = $Text + $script:StatusPill.BackColor = $Color +} + +function Add-AnimatedButton { + param( + [Parameter(Mandatory)][Windows.Forms.Button]$Button, + [Parameter(Mandatory)][Drawing.Color]$Normal, + [Parameter(Mandatory)][Drawing.Color]$Hover + ) + + $Button.FlatStyle = "Flat" + $Button.FlatAppearance.BorderColor = $colors.Border + $Button.FlatAppearance.BorderSize = 1 + $Button.BackColor = $Normal + $Button.ForeColor = $colors.Text + $Button.Cursor = [Windows.Forms.Cursors]::Hand + $Button.Add_MouseEnter({ param($sender, $eventArgs) $sender.BackColor = $Hover }) + $Button.Add_MouseLeave({ param($sender, $eventArgs) $sender.BackColor = $Normal }) + $Button.Add_MouseDown({ param($sender, $eventArgs) $sender.Location = [Drawing.Point]::new($sender.Location.X, $sender.Location.Y + 1) }) + $Button.Add_MouseUp({ param($sender, $eventArgs) $sender.Location = [Drawing.Point]::new($sender.Location.X, $sender.Location.Y - 1) }) +} + +function New-Label { + param( + [string]$Text, + [int]$X, + [int]$Y, + [int]$Width = 220, + [int]$Height = 24, + [Drawing.Color]$Color = $colors.Muted, + [Drawing.Font]$Font = $null + ) + + $label = [Windows.Forms.Label]::new() + $label.Text = $Text + $label.Location = [Drawing.Point]::new($X, $Y) + $label.Size = [Drawing.Size]::new($Width, $Height) + $label.ForeColor = $Color + if ($Font) { $label.Font = $Font } + $label +} + +function Update-TrustStatus { try { + Set-Busy $true $rootCertificate = Get-MrTrustCertificate -Path $script:RootCertificatePath $publisherCertificate = Get-MrTrustCertificate -Path $script:PublisherCertificatePath $scope = Get-TrustScope @@ -74,79 +137,58 @@ function Refresh-MrTrustStatus { $script:RootThumbprintLabel.Text = $rootCertificate.Thumbprint $script:PublisherThumbprintLabel.Text = $publisherCertificate.Thumbprint $script:ExpiryLabel.Text = $rootCertificate.NotAfter.ToString("yyyy-MM-dd") + $script:ScopeValueLabel.Text = $scope if ($rootInstalled -and $publisherInstalled) { - Set-StatusText "Trusted" - $script:StatusPill.BackColor = [Drawing.Color]::FromArgb(28, 185, 111) + Set-StatusText -Text "Trusted" -Color $colors.Green + $script:TrustSummaryLabel.Text = "MrSphay public trust is installed for $scope." } else { - Set-StatusText "Not installed" - $script:StatusPill.BackColor = [Drawing.Color]::FromArgb(242, 153, 74) + Set-StatusText -Text "Not installed" -Color $colors.Orange + $script:TrustSummaryLabel.Text = "Trust is not fully installed for $scope." } } catch { - Set-StatusText $_.Exception.Message - $script:StatusPill.BackColor = [Drawing.Color]::FromArgb(235, 87, 87) + Set-StatusText -Text "Error" -Color $colors.Red + $script:TrustSummaryLabel.Text = $_.Exception.Message + } + finally { + Set-Busy $false } } function Install-MrTrustCertificates { $scope = Get-TrustScope if ($scope -eq "LocalMachine" -and -not (Test-IsAdministrator)) { - [Windows.Forms.MessageBox]::Show( - "All-users trust requires running PowerShell as Administrator.", - "MrTrust", - [Windows.Forms.MessageBoxButtons]::OK, - [Windows.Forms.MessageBoxIcon]::Warning - ) | Out-Null + [Windows.Forms.MessageBox]::Show("All-users trust requires running MrTrust as Administrator.", "MrTrust", "OK", "Warning") | Out-Null return } $rootCertificate = Get-MrTrustCertificate -Path $script:RootCertificatePath $publisherCertificate = Get-MrTrustCertificate -Path $script:PublisherCertificatePath + $message = "Install MrSphay trust for $scope?`r`n`r`nRoot:`r`n$($rootCertificate.Thumbprint)`r`n`r`nPublisher:`r`n$($publisherCertificate.Thumbprint)`r`n`r`nThis does not disable Defender or SmartScreen." + $result = [Windows.Forms.MessageBox]::Show($message, "Install MrTrust", "YesNo", "Warning") + if ($result -ne [Windows.Forms.DialogResult]::Yes) { return } - $message = "Install MrSphay trust for $scope?`r`n`r`nRoot:`r`n$($rootCertificate.Thumbprint)`r`n`r`nPublisher:`r`n$($publisherCertificate.Thumbprint)`r`n`r`nOnly continue if you trust software signed by MrSphay." - $result = [Windows.Forms.MessageBox]::Show( - $message, - "Install MrTrust", - [Windows.Forms.MessageBoxButtons]::YesNo, - [Windows.Forms.MessageBoxIcon]::Warning - ) - - if ($result -ne [Windows.Forms.DialogResult]::Yes) { - return - } - + Set-Busy $true Import-Certificate -FilePath $script:RootCertificatePath -CertStoreLocation (Get-StorePath -Scope $scope -Store "Root") | Out-Null Import-Certificate -FilePath $script:PublisherCertificatePath -CertStoreLocation (Get-StorePath -Scope $scope -Store "TrustedPublisher") | Out-Null - Refresh-MrTrustStatus + Update-TrustStatus } function Remove-MrTrustCertificates { $scope = Get-TrustScope if ($scope -eq "LocalMachine" -and -not (Test-IsAdministrator)) { - [Windows.Forms.MessageBox]::Show( - "All-users removal requires running PowerShell as Administrator.", - "MrTrust", - [Windows.Forms.MessageBoxButtons]::OK, - [Windows.Forms.MessageBoxIcon]::Warning - ) | Out-Null + [Windows.Forms.MessageBox]::Show("All-users removal requires running MrTrust as Administrator.", "MrTrust", "OK", "Warning") | Out-Null return } + $result = [Windows.Forms.MessageBox]::Show("Remove MrSphay trust for $scope?", "Remove MrTrust", "YesNo", "Question") + if ($result -ne [Windows.Forms.DialogResult]::Yes) { return } + + Set-Busy $true $rootCertificate = Get-MrTrustCertificate -Path $script:RootCertificatePath $publisherCertificate = Get-MrTrustCertificate -Path $script:PublisherCertificatePath - $result = [Windows.Forms.MessageBox]::Show( - "Remove MrSphay trust for $scope?", - "Remove MrTrust", - [Windows.Forms.MessageBoxButtons]::YesNo, - [Windows.Forms.MessageBoxIcon]::Question - ) - - if ($result -ne [Windows.Forms.DialogResult]::Yes) { - return - } - $targets = @( [pscustomobject]@{ Store = "Root"; Thumbprint = $rootCertificate.Thumbprint }, [pscustomobject]@{ Store = "TrustedPublisher"; Thumbprint = $publisherCertificate.Thumbprint } @@ -159,7 +201,86 @@ function Remove-MrTrustCertificates { Remove-Item } - Refresh-MrTrustStatus + Update-TrustStatus +} + +function Test-MarkOfTheWeb { + param([Parameter(Mandatory)][string]$Path) + + try { + $stream = Get-Content -LiteralPath $Path -Stream Zone.Identifier -ErrorAction Stop + ($stream -join "`n") -match "ZoneId\s*=\s*[3-4]" + } + catch { + $false + } +} + +function Get-SmartScreenExplanation { + param( + [bool]$SignedByMrSphay, + [bool]$HasMotw + ) + + if ($SignedByMrSphay -and $HasMotw) { + "Publisher trust can be valid while SmartScreen still warns because the downloaded file has Internet origin and low Microsoft reputation." + } + elseif ($SignedByMrSphay) { + "The publisher matches MrSphay. SmartScreen may still warn until Microsoft reputation builds for this exact app and publisher." + } + elseif ($HasMotw) { + "This file came from the Internet and is not signed by MrSphay. SmartScreen warnings are expected." + } + else { + "MrTrust can only help with MrSphay-signed files. SmartScreen reputation is separate from local certificate trust." + } +} + +function Test-SelectedFile { + param([Parameter(Mandatory)][string]$Path) + + Set-Busy $true + try { + if (-not (Test-Path -LiteralPath $Path -PathType Leaf)) { + throw "File not found: $Path" + } + + $signature = Get-AuthenticodeSignature -LiteralPath $Path + $hasMotw = Test-MarkOfTheWeb -Path $Path + $signer = $signature.SignerCertificate + $signedByMrSphay = $false + if ($signer) { + $signedByMrSphay = $signer.Thumbprint -eq "A024A89200469F099EC4A172B4F96F6428AFD41B" -or $signer.Subject -like "*MrSphay*" + } + + $script:FileNameLabel.Text = [IO.Path]::GetFileName($Path) + $script:FilePathLabel.Text = $Path + $script:SignatureStatusLabel.Text = "$($signature.Status)" + $script:SignerLabel.Text = if ($signer) { $signer.Subject } else { "No signer certificate" } + $script:MrSphayMatchLabel.Text = if ($signedByMrSphay) { "Yes" } else { "No" } + $script:MotwLabel.Text = if ($hasMotw) { "Yes" } else { "No" } + $script:SmartScreenLabel.Text = Get-SmartScreenExplanation -SignedByMrSphay $signedByMrSphay -HasMotw $hasMotw + + if ($signedByMrSphay -and $signature.Status -eq "Valid") { + $script:FileVerdictLabel.Text = "Looks good: signed by MrSphay and locally valid." + $script:FileVerdictLabel.ForeColor = $colors.Green + } + elseif ($signedByMrSphay) { + $script:FileVerdictLabel.Text = "Signed by MrSphay, but local validation is not fully valid: $($signature.Status)" + $script:FileVerdictLabel.ForeColor = $colors.Orange + } + else { + $script:FileVerdictLabel.Text = "Not a MrSphay-signed file." + $script:FileVerdictLabel.ForeColor = $colors.Red + } + } + catch { + $script:FileVerdictLabel.Text = $_.Exception.Message + $script:FileVerdictLabel.ForeColor = $colors.Red + } + finally { + Set-Busy $false + } } [Windows.Forms.Application]::EnableVisualStyles() @@ -167,9 +288,9 @@ function Remove-MrTrustCertificates { $form = [Windows.Forms.Form]::new() $form.Text = "MrTrust" $form.StartPosition = "CenterScreen" -$form.ClientSize = [Drawing.Size]::new(900, 560) -$form.MinimumSize = [Drawing.Size]::new(860, 540) -$form.BackColor = [Drawing.Color]::FromArgb(22, 26, 29) +$form.ClientSize = [Drawing.Size]::new(980, 660) +$form.MinimumSize = [Drawing.Size]::new(920, 620) +$form.BackColor = $colors.Background $form.Font = [Drawing.Font]::new("Segoe UI", 10) if (Test-Path -LiteralPath $script:IconPath) { $form.Icon = [Drawing.Icon]::new($script:IconPath) @@ -177,18 +298,18 @@ if (Test-Path -LiteralPath $script:IconPath) { $header = [Windows.Forms.Panel]::new() $header.Dock = "Top" -$header.Height = 124 -$header.BackColor = [Drawing.Color]::FromArgb(27, 32, 35) +$header.Height = 126 +$header.BackColor = $colors.Panel $form.Controls.Add($header) $accent = [Windows.Forms.Panel]::new() $accent.Dock = "Left" $accent.Width = 8 -$accent.BackColor = [Drawing.Color]::FromArgb(28, 185, 111) +$accent.BackColor = $colors.Green $header.Controls.Add($accent) $logoBox = [Windows.Forms.PictureBox]::new() -$logoBox.Size = [Drawing.Size]::new(44, 44) +$logoBox.Size = [Drawing.Size]::new(46, 46) $logoBox.Location = [Drawing.Point]::new(34, 30) $logoBox.SizeMode = "StretchImage" if (Test-Path -LiteralPath $script:IconPath) { @@ -196,151 +317,213 @@ if (Test-Path -LiteralPath $script:IconPath) { } $header.Controls.Add($logoBox) -$title = [Windows.Forms.Label]::new() -$title.Text = "MrTrust" -$title.ForeColor = [Drawing.Color]::White -$title.Font = [Drawing.Font]::new("Segoe UI", 24, [Drawing.FontStyle]::Bold) -$title.AutoSize = $true -$title.Location = [Drawing.Point]::new(92, 24) +$title = New-Label -Text "MrTrust" -X 96 -Y 22 -Width 260 -Height 48 -Color $colors.Text -Font ([Drawing.Font]::new("Segoe UI", 25, [Drawing.FontStyle]::Bold)) $header.Controls.Add($title) -$subtitle = [Windows.Forms.Label]::new() -$subtitle.Text = "Trust setup for MrSphay signed Windows apps" -$subtitle.ForeColor = [Drawing.Color]::FromArgb(177, 190, 183) -$subtitle.AutoSize = $true -$subtitle.Location = [Drawing.Point]::new(96, 74) +$subtitle = New-Label -Text "Trust diagnostics for MrSphay signed Windows apps" -X 100 -Y 76 -Width 520 -Height 24 -Color $colors.Muted $header.Controls.Add($subtitle) -$statusText = [Windows.Forms.Label]::new() -$statusText.Text = "Status" -$statusText.ForeColor = [Drawing.Color]::FromArgb(177, 190, 183) -$statusText.AutoSize = $true -$statusText.Location = [Drawing.Point]::new(646, 32) +$statusText = New-Label -Text "Status" -X 720 -Y 31 -Width 180 -Height 22 $header.Controls.Add($statusText) $script:StatusPill = [Windows.Forms.Panel]::new() $script:StatusPill.Size = [Drawing.Size]::new(16, 16) -$script:StatusPill.Location = [Drawing.Point]::new(646, 62) -$script:StatusPill.BackColor = [Drawing.Color]::FromArgb(242, 153, 74) +$script:StatusPill.Location = [Drawing.Point]::new(720, 63) +$script:StatusPill.BackColor = $colors.Orange $header.Controls.Add($script:StatusPill) -$script:StatusLabel = [Windows.Forms.Label]::new() -$script:StatusLabel.Text = "Checking..." -$script:StatusLabel.ForeColor = [Drawing.Color]::FromArgb(225, 231, 227) -$script:StatusLabel.AutoSize = $false +$script:StatusLabel = New-Label -Text "Checking..." -X 748 -Y 58 -Width 190 -Height 28 -Color $colors.Text $script:StatusLabel.AutoEllipsis = $true -$script:StatusLabel.Location = [Drawing.Point]::new(674, 57) -$script:StatusLabel.Size = [Drawing.Size]::new(190, 28) $header.Controls.Add($script:StatusLabel) -$content = [Windows.Forms.Panel]::new() -$content.Dock = "Fill" -$content.Padding = [Windows.Forms.Padding]::new(30) -$content.BackColor = [Drawing.Color]::FromArgb(22, 26, 29) -$form.Controls.Add($content) +$script:ProgressBar = [Windows.Forms.ProgressBar]::new() +$script:ProgressBar.Location = [Drawing.Point]::new(100, 108) +$script:ProgressBar.Size = [Drawing.Size]::new(820, 5) +$script:ProgressBar.Visible = $false +$header.Controls.Add($script:ProgressBar) -$infoPanel = [Windows.Forms.Panel]::new() -$infoPanel.BackColor = [Drawing.Color]::FromArgb(31, 37, 40) -$infoPanel.Size = [Drawing.Size]::new(820, 226) -$infoPanel.Location = [Drawing.Point]::new(40, 34) -$content.Controls.Add($infoPanel) +$tabControl = [Windows.Forms.TabControl]::new() +$tabControl.Dock = "Fill" +$tabControl.Appearance = "Normal" +$tabControl.BackColor = $colors.Background +$tabControl.ForeColor = $colors.Text +$form.Controls.Add($tabControl) -$scopeLabel = [Windows.Forms.Label]::new() -$scopeLabel.Text = "Scope" -$scopeLabel.ForeColor = [Drawing.Color]::FromArgb(177, 190, 183) -$scopeLabel.Location = [Drawing.Point]::new(24, 24) -$scopeLabel.AutoSize = $true -$infoPanel.Controls.Add($scopeLabel) +$trustTab = [Windows.Forms.TabPage]::new() +$trustTab.Text = "Trust" +$trustTab.BackColor = $colors.Background +$tabControl.TabPages.Add($trustTab) + +$diagnosticsTab = [Windows.Forms.TabPage]::new() +$diagnosticsTab.Text = "Diagnostics" +$diagnosticsTab.BackColor = $colors.Background +$tabControl.TabPages.Add($diagnosticsTab) + +$helpTab = [Windows.Forms.TabPage]::new() +$helpTab.Text = "SmartScreen" +$helpTab.BackColor = $colors.Background +$tabControl.TabPages.Add($helpTab) + +$trustPanel = [Windows.Forms.Panel]::new() +$trustPanel.BackColor = $colors.Panel +$trustPanel.Size = [Drawing.Size]::new(880, 245) +$trustPanel.Location = [Drawing.Point]::new(36, 34) +$trustTab.Controls.Add($trustPanel) + +$scopeLabel = New-Label -Text "Scope" -X 26 -Y 24 +$trustPanel.Controls.Add($scopeLabel) $script:AllUsersCheckBox = [Windows.Forms.CheckBox]::new() $script:AllUsersCheckBox.Text = "Install for all users (requires Administrator)" -$script:AllUsersCheckBox.ForeColor = [Drawing.Color]::FromArgb(225, 231, 227) -$script:AllUsersCheckBox.Location = [Drawing.Point]::new(24, 50) +$script:AllUsersCheckBox.ForeColor = $colors.Text +$script:AllUsersCheckBox.Location = [Drawing.Point]::new(26, 50) $script:AllUsersCheckBox.AutoSize = $true $script:AllUsersCheckBox.FlatStyle = "Flat" -$script:AllUsersCheckBox.Add_CheckedChanged({ Refresh-MrTrustStatus }) -$infoPanel.Controls.Add($script:AllUsersCheckBox) +$script:AllUsersCheckBox.Add_CheckedChanged({ Update-TrustStatus }) +$trustPanel.Controls.Add($script:AllUsersCheckBox) -$rootLabel = [Windows.Forms.Label]::new() -$rootLabel.Text = "Root thumbprint" -$rootLabel.ForeColor = [Drawing.Color]::FromArgb(177, 190, 183) -$rootLabel.Location = [Drawing.Point]::new(24, 92) -$rootLabel.AutoSize = $true -$infoPanel.Controls.Add($rootLabel) +$trustPanel.Controls.Add((New-Label -Text "Root thumbprint" -X 26 -Y 92)) +$script:RootThumbprintLabel = New-Label -Text "-" -X 205 -Y 92 -Width 580 -Height 24 -Color $colors.Text -Font ([Drawing.Font]::new("Consolas", 9)) +$trustPanel.Controls.Add($script:RootThumbprintLabel) -$script:RootThumbprintLabel = [Windows.Forms.Label]::new() -$script:RootThumbprintLabel.Text = "-" -$script:RootThumbprintLabel.ForeColor = [Drawing.Color]::FromArgb(225, 231, 227) -$script:RootThumbprintLabel.Font = [Drawing.Font]::new("Consolas", 9) -$script:RootThumbprintLabel.Location = [Drawing.Point]::new(180, 92) -$script:RootThumbprintLabel.AutoSize = $true -$infoPanel.Controls.Add($script:RootThumbprintLabel) +$trustPanel.Controls.Add((New-Label -Text "Publisher thumbprint" -X 26 -Y 126)) +$script:PublisherThumbprintLabel = New-Label -Text "-" -X 205 -Y 126 -Width 580 -Height 24 -Color $colors.Text -Font ([Drawing.Font]::new("Consolas", 9)) +$trustPanel.Controls.Add($script:PublisherThumbprintLabel) -$publisherLabel = [Windows.Forms.Label]::new() -$publisherLabel.Text = "Publisher thumbprint" -$publisherLabel.ForeColor = [Drawing.Color]::FromArgb(177, 190, 183) -$publisherLabel.Location = [Drawing.Point]::new(24, 128) -$publisherLabel.AutoSize = $true -$infoPanel.Controls.Add($publisherLabel) +$trustPanel.Controls.Add((New-Label -Text "Expires" -X 26 -Y 160)) +$script:ExpiryLabel = New-Label -Text "-" -X 205 -Y 160 -Width 200 -Height 24 -Color $colors.Text +$trustPanel.Controls.Add($script:ExpiryLabel) -$script:PublisherThumbprintLabel = [Windows.Forms.Label]::new() -$script:PublisherThumbprintLabel.Text = "-" -$script:PublisherThumbprintLabel.ForeColor = [Drawing.Color]::FromArgb(225, 231, 227) -$script:PublisherThumbprintLabel.Font = [Drawing.Font]::new("Consolas", 9) -$script:PublisherThumbprintLabel.Location = [Drawing.Point]::new(180, 128) -$script:PublisherThumbprintLabel.AutoSize = $true -$infoPanel.Controls.Add($script:PublisherThumbprintLabel) +$trustPanel.Controls.Add((New-Label -Text "Active scope" -X 26 -Y 194)) +$script:ScopeValueLabel = New-Label -Text "-" -X 205 -Y 194 -Width 200 -Height 24 -Color $colors.Text +$trustPanel.Controls.Add($script:ScopeValueLabel) -$expiryLabelTitle = [Windows.Forms.Label]::new() -$expiryLabelTitle.Text = "Expires" -$expiryLabelTitle.ForeColor = [Drawing.Color]::FromArgb(177, 190, 183) -$expiryLabelTitle.Location = [Drawing.Point]::new(24, 164) -$expiryLabelTitle.AutoSize = $true -$infoPanel.Controls.Add($expiryLabelTitle) - -$script:ExpiryLabel = [Windows.Forms.Label]::new() -$script:ExpiryLabel.Text = "-" -$script:ExpiryLabel.ForeColor = [Drawing.Color]::FromArgb(225, 231, 227) -$script:ExpiryLabel.Location = [Drawing.Point]::new(180, 164) -$script:ExpiryLabel.AutoSize = $true -$infoPanel.Controls.Add($script:ExpiryLabel) +$script:TrustSummaryLabel = New-Label -Text "Checking trust state..." -X 36 -Y 306 -Width 860 -Height 42 -Color $colors.Muted +$trustTab.Controls.Add($script:TrustSummaryLabel) $installButton = [Windows.Forms.Button]::new() $installButton.Text = "Install trust" -$installButton.BackColor = [Drawing.Color]::FromArgb(28, 185, 111) -$installButton.ForeColor = [Drawing.Color]::White -$installButton.FlatStyle = "Flat" -$installButton.Size = [Drawing.Size]::new(180, 46) -$installButton.Location = [Drawing.Point]::new(40, 292) +$installButton.Size = [Drawing.Size]::new(180, 48) +$installButton.Location = [Drawing.Point]::new(36, 372) +Add-AnimatedButton -Button $installButton -Normal $colors.Green -Hover $colors.GreenHover $installButton.Add_Click({ Install-MrTrustCertificates }) -$content.Controls.Add($installButton) +$trustTab.Controls.Add($installButton) $removeButton = [Windows.Forms.Button]::new() $removeButton.Text = "Remove trust" -$removeButton.BackColor = [Drawing.Color]::FromArgb(44, 52, 56) -$removeButton.ForeColor = [Drawing.Color]::FromArgb(225, 231, 227) -$removeButton.FlatStyle = "Flat" -$removeButton.Size = [Drawing.Size]::new(180, 46) -$removeButton.Location = [Drawing.Point]::new(240, 292) +$removeButton.Size = [Drawing.Size]::new(180, 48) +$removeButton.Location = [Drawing.Point]::new(238, 372) +Add-AnimatedButton -Button $removeButton -Normal $colors.PanelAlt -Hover $colors.Border $removeButton.Add_Click({ Remove-MrTrustCertificates }) -$content.Controls.Add($removeButton) +$trustTab.Controls.Add($removeButton) $refreshButton = [Windows.Forms.Button]::new() $refreshButton.Text = "Refresh" -$refreshButton.BackColor = [Drawing.Color]::FromArgb(44, 52, 56) -$refreshButton.ForeColor = [Drawing.Color]::FromArgb(225, 231, 227) -$refreshButton.FlatStyle = "Flat" -$refreshButton.Size = [Drawing.Size]::new(140, 46) -$refreshButton.Location = [Drawing.Point]::new(440, 292) -$refreshButton.Add_Click({ Refresh-MrTrustStatus }) -$content.Controls.Add($refreshButton) +$refreshButton.Size = [Drawing.Size]::new(140, 48) +$refreshButton.Location = [Drawing.Point]::new(440, 372) +Add-AnimatedButton -Button $refreshButton -Normal $colors.PanelAlt -Hover $colors.Border +$refreshButton.Add_Click({ Update-TrustStatus }) +$trustTab.Controls.Add($refreshButton) -$note = [Windows.Forms.Label]::new() -$note.Text = "MrTrust installs public certificates only. It does not disable Defender, SmartScreen, UAC, or enterprise policies." -$note.ForeColor = [Drawing.Color]::FromArgb(177, 190, 183) -$note.Location = [Drawing.Point]::new(40, 376) -$note.Size = [Drawing.Size]::new(820, 48) -$content.Controls.Add($note) +$note = New-Label -Text "MrTrust installs public certificates only. It does not disable Defender, SmartScreen, UAC, or enterprise policies." -X 36 -Y 456 -Width 880 -Height 46 -Color $colors.Muted +$trustTab.Controls.Add($note) -$form.Add_Shown({ Refresh-MrTrustStatus }) +$filePanel = [Windows.Forms.Panel]::new() +$filePanel.BackColor = $colors.Panel +$filePanel.Size = [Drawing.Size]::new(880, 420) +$filePanel.Location = [Drawing.Point]::new(36, 34) +$diagnosticsTab.Controls.Add($filePanel) + +$chooseButton = [Windows.Forms.Button]::new() +$chooseButton.Text = "Choose .exe or .msi" +$chooseButton.Size = [Drawing.Size]::new(190, 44) +$chooseButton.Location = [Drawing.Point]::new(24, 24) +Add-AnimatedButton -Button $chooseButton -Normal $colors.Green -Hover $colors.GreenHover +$filePanel.Controls.Add($chooseButton) + +$scanButton = [Windows.Forms.Button]::new() +$scanButton.Text = "Scan file" +$scanButton.Size = [Drawing.Size]::new(130, 44) +$scanButton.Location = [Drawing.Point]::new(232, 24) +Add-AnimatedButton -Button $scanButton -Normal $colors.PanelAlt -Hover $colors.Border +$filePanel.Controls.Add($scanButton) + +$script:FileVerdictLabel = New-Label -Text "Choose a Windows installer or executable to inspect." -X 24 -Y 88 -Width 820 -Height 30 -Color $colors.Muted -Font ([Drawing.Font]::new("Segoe UI", 11, [Drawing.FontStyle]::Bold)) +$filePanel.Controls.Add($script:FileVerdictLabel) + +$filePanel.Controls.Add((New-Label -Text "File" -X 24 -Y 136)) +$script:FileNameLabel = New-Label -Text "-" -X 210 -Y 136 -Width 620 -Height 24 -Color $colors.Text +$filePanel.Controls.Add($script:FileNameLabel) + +$filePanel.Controls.Add((New-Label -Text "Path" -X 24 -Y 170)) +$script:FilePathLabel = New-Label -Text "-" -X 210 -Y 170 -Width 620 -Height 40 -Color $colors.Text +$script:FilePathLabel.AutoEllipsis = $true +$filePanel.Controls.Add($script:FilePathLabel) + +$filePanel.Controls.Add((New-Label -Text "Signature status" -X 24 -Y 222)) +$script:SignatureStatusLabel = New-Label -Text "-" -X 210 -Y 222 -Width 620 -Height 24 -Color $colors.Text +$filePanel.Controls.Add($script:SignatureStatusLabel) + +$filePanel.Controls.Add((New-Label -Text "Signer" -X 24 -Y 256)) +$script:SignerLabel = New-Label -Text "-" -X 210 -Y 256 -Width 620 -Height 36 -Color $colors.Text +$script:SignerLabel.AutoEllipsis = $true +$filePanel.Controls.Add($script:SignerLabel) + +$filePanel.Controls.Add((New-Label -Text "MrSphay match" -X 24 -Y 306)) +$script:MrSphayMatchLabel = New-Label -Text "-" -X 210 -Y 306 -Width 180 -Height 24 -Color $colors.Text +$filePanel.Controls.Add($script:MrSphayMatchLabel) + +$filePanel.Controls.Add((New-Label -Text "Mark-of-the-Web" -X 24 -Y 340)) +$script:MotwLabel = New-Label -Text "-" -X 210 -Y 340 -Width 180 -Height 24 -Color $colors.Text +$filePanel.Controls.Add($script:MotwLabel) + +$filePanel.Controls.Add((New-Label -Text "SmartScreen note" -X 24 -Y 374)) +$script:SmartScreenLabel = New-Label -Text "-" -X 210 -Y 374 -Width 620 -Height 40 -Color $colors.Muted +$filePanel.Controls.Add($script:SmartScreenLabel) + +$chooseButton.Add_Click({ + $dialog = [Windows.Forms.OpenFileDialog]::new() + $dialog.Filter = "Windows apps and installers (*.exe;*.msi;*.dll;*.cat)|*.exe;*.msi;*.dll;*.cat|All files (*.*)|*.*" + if ($dialog.ShowDialog() -eq [Windows.Forms.DialogResult]::OK) { + $script:SelectedFilePath = $dialog.FileName + Test-SelectedFile -Path $script:SelectedFilePath + } +}) +$scanButton.Add_Click({ + if ($script:SelectedFilePath) { + Test-SelectedFile -Path $script:SelectedFilePath + } +}) + +$helpPanel = [Windows.Forms.Panel]::new() +$helpPanel.BackColor = $colors.Panel +$helpPanel.Size = [Drawing.Size]::new(880, 420) +$helpPanel.Location = [Drawing.Point]::new(36, 34) +$helpTab.Controls.Add($helpPanel) + +$helpTitle = New-Label -Text "Why SmartScreen can still appear" -X 24 -Y 24 -Width 780 -Height 34 -Color $colors.Text -Font ([Drawing.Font]::new("Segoe UI", 14, [Drawing.FontStyle]::Bold)) +$helpPanel.Controls.Add($helpTitle) + +$helpText = @" +MrTrust handles local certificate trust. SmartScreen also uses Microsoft reputation. + +If Windows shows "Publisher: MrSphay Code Signing", the signature identity is being recognized. + +A red SmartScreen dialog can still appear when a file is new, downloaded from the Internet, rarely seen, or has not built enough Microsoft reputation yet. + +MrTrust will not disable SmartScreen. It can show whether a file is signed, whether it matches MrSphay, and whether Mark-of-the-Web is present. +"@ +$helpBody = New-Label -Text $helpText -X 24 -Y 78 -Width 820 -Height 250 -Color $colors.Muted +$helpPanel.Controls.Add($helpBody) + +$pulseTimer = [Windows.Forms.Timer]::new() +$pulseTimer.Interval = 80 +$pulseTimer.Add_Tick({ + $script:CurrentAccent = ($script:CurrentAccent + 1) % 40 + $value = 150 + [Math]::Abs(20 - $script:CurrentAccent) * 3 + $accent.BackColor = [Drawing.Color]::FromArgb(28, [Math]::Min(220, $value), 111) +}) +$pulseTimer.Start() + +$form.Add_Shown({ Update-TrustStatus }) [Windows.Forms.Application]::Run($form)