Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 25 additions & 7 deletions src-tauri/client-cli/src/brand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,33 @@
//! Shown when invoked with no arguments or with `--help`.
//! Suppressed for `--version` (which must stay grep-friendly).
//!
//! Two assets:
//! The logo is emitted on non-Windows platforms only. Its art uses
//! fine-grained Unicode block glyphs (eighths/quadrant blocks) that many
//! Windows console fonts can't render, so Windows shows just the
//! copyright + version line.
//!
//! Two assets (non-Windows):
//! - assets/logo-color.ansi -- ANSI block-character art,
//! used when stdout is an interactive TTY
//! - assets/logo-mono.txt -- plain ASCII fallback (no ANSI),
//! used when output is piped/redirected or NO_COLOR is set
//!
//! Both assets are embedded at compile time via `include_str!`.

#[cfg(not(windows))]
use owo_colors::{OwoColorize, Stream};

#[cfg(not(windows))]
const LOGO_COLOR: &str = include_str!("../assets/logo-color.ansi");
#[cfg(not(windows))]
const LOGO_MONO: &str = include_str!("../assets/logo-mono.txt");

const COPYRIGHT: &str = "Copyright (C) 2026 Defguard Sp. z o.o.";

/// Print logo + copyright + project name/version to stdout. Picks
/// the colored variant on an interactive TTY, the mono fallback
/// Print logo + copyright + project name/version to stdout. Picks the
/// colored logo variant on an interactive TTY and the mono fallback
/// otherwise (so `defguard-cli --help | cat` stays clean ASCII).
#[cfg(not(windows))]
pub fn print_banner() {
// owo-colors' supports-colors detection drives the choice: if
// stdout supports color, emit the ANSI variant; otherwise mono.
Expand All @@ -38,13 +47,22 @@ pub fn print_banner() {

let project = common::version_string("defguard-cli");
if use_color {
let p = project.bright_yellow().bold().to_string();
let c = COPYRIGHT.dimmed().to_string();
println!(" {p}");
println!(" {c}");
println!(" {}", project.bright_yellow().bold());
println!(" {}", COPYRIGHT.dimmed());
} else {
println!(" {project}");
println!(" {COPYRIGHT}");
}
println!();
}

/// Print copyright + project name/version to stdout. The logo is skipped
/// on Windows: its art relies on Unicode block glyphs that many Windows
/// console fonts can't render, and the console may not interpret ANSI.
#[cfg(windows)]
pub fn print_banner() {
let project = common::version_string("defguard-cli");
println!(" {project}");
println!(" {COPYRIGHT}");
println!();
}
10 changes: 10 additions & 0 deletions src-tauri/resources-windows/fragments/cli.wxs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Fragment>
<DirectoryRef Id="INSTALLDIR">
<Component Id="DefguardCliFragment" Guid="*">
<File KeyPath="yes" Id="DefguardCliFile" Source="..\..\defguard-cli.exe" />
</Component>
</DirectoryRef>
</Fragment>
</Wix>
55 changes: 55 additions & 0 deletions src-tauri/resources-windows/scripts/Sign-Binaries.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
$ErrorActionPreference = 'Stop'

$tauriConfigPath = Join-Path $PSScriptRoot '..\..\tauri.conf.json'
$tauriConfig = Get-Content $tauriConfigPath -Raw | ConvertFrom-Json
$windowsConfig = $tauriConfig.bundle.windows

$thumbprint = $windowsConfig.certificateThumbprint

$timestampUrl = if ($env:DEFGUARD_WINDOWS_TIMESTAMP_URL) {
$env:DEFGUARD_WINDOWS_TIMESTAMP_URL
} else {
$windowsConfig.timestampUrl
}

$digestAlgorithm = if ($windowsConfig.digestAlgorithm) {
$windowsConfig.digestAlgorithm.ToUpperInvariant()
} else {
'SHA256'
}

if (-not $thumbprint) {
throw 'Windows certificate thumbprint is not configured.'
}

# Resolve signtool to a plain path string. Get-Command returns a
# CommandInfo (use .Source); the Windows Kits fallback returns a
# FileInfo (use .FullName).
$signtoolPath = (Get-Command signtool.exe -ErrorAction SilentlyContinue).Source
if (-not $signtoolPath) {
$signtoolPath = Get-ChildItem 'C:\Program Files (x86)\Windows Kits\10\bin' -Recurse -Filter signtool.exe |
Where-Object { $_.FullName -match '\\x64\\signtool\.exe$' } |
Sort-Object FullName -Descending |
Select-Object -First 1 -ExpandProperty FullName
}

if (-not $signtoolPath) {
throw 'signtool.exe was not found.'
}

$binaries = @(
'target\release\defguard-cli.exe',
'target\release\defguard-service.exe'
)

foreach ($binary in $binaries) {
if (-not (Test-Path $binary)) {
throw "Binary not found: $binary"
}

Write-Host "Signing $binary"
& $signtoolPath sign /sha1 $thumbprint /fd $digestAlgorithm /tr $timestampUrl /td $digestAlgorithm $binary
if ($LASTEXITCODE -ne 0) {
throw "Failed to sign $binary"
}
}
2 changes: 2 additions & 0 deletions src-tauri/tauri.conf.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,12 @@
"dialogImagePath": "./resources-windows/msi/side_banner.png",
"fragmentPaths": [
"./resources-windows/fragments/service.wxs",
"./resources-windows/fragments/cli.wxs",
"./resources-windows/fragments/provisioning.wxs"
],
"componentRefs": [
"DefguardServiceFragment",
"DefguardCliFragment",
"ProvisioningScriptFragment"
],
"template": "./resources-windows/msi/main.wxs"
Expand Down
6 changes: 6 additions & 0 deletions src-tauri/tauri.windows.conf.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
{
"build": {
"beforeBundleCommand": {
"cwd": ".",
"script": "powershell -ExecutionPolicy Bypass -File ./resources-windows/scripts/Sign-Binaries.ps1"
}
},
"bundle": {
"targets": ["msi"],
"resources": [
Expand Down
Loading