diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 2a5ccab..3e453a3 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -13,8 +13,14 @@ on:
description: "Hotfix patch number, for example 1 or 2. Use 0 for a normal build."
required: false
default: "0"
+ sign_windows_test:
+ description: "Submit the Windows installer to SignPath using test-signing."
+ required: false
+ type: boolean
+ default: false
permissions:
+ actions: read
contents: write
env:
@@ -410,6 +416,52 @@ jobs:
run: |
& "${{ github.workspace }}\scripts\windows\pkg_x64.ps1" $env:VERSION_NUM
+ - name: Upload unsigned Windows installer for test signing
+ if: github.event_name == 'workflow_dispatch' && inputs.sign_windows_test
+ id: upload-unsigned-windows-installer
+ uses: actions/upload-artifact@v7
+ with:
+ path: ${{ github.workspace }}/scripts/windows/crossdesk-win-x64-${{ env.VERSION_NUM }}.exe
+ archive: false
+ if-no-files-found: error
+ retention-days: 1
+
+ - name: Sign Windows installer with SignPath test certificate
+ if: github.event_name == 'workflow_dispatch' && inputs.sign_windows_test
+ uses: signpath/github-action-submit-signing-request@v2
+ with:
+ api-token: ${{ secrets.SIGNPATH_API_TOKEN }}
+ organization-id: ${{ vars.SIGNPATH_ORGANIZATION_ID }}
+ project-slug: crossdesk
+ signing-policy-slug: test-signing
+ github-artifact-id: ${{ steps.upload-unsigned-windows-installer.outputs.artifact-id }}
+ wait-for-completion: true
+ output-artifact-directory: ${{ github.workspace }}\signpath\signed-installer
+ skip-decompress: true
+ parameters: |
+ version: ${{ toJSON(env.VERSION_NUM) }}
+
+ - name: Verify and use test-signed Windows installer
+ if: github.event_name == 'workflow_dispatch' && inputs.sign_windows_test
+ shell: pwsh
+ run: |
+ $installerName = "crossdesk-win-x64-${{ env.VERSION_NUM }}.exe"
+ $signedInstaller = Join-Path "${{ github.workspace }}\signpath\signed-installer" $installerName
+ $destination = Join-Path "${{ github.workspace }}\scripts\windows" $installerName
+
+ if (!(Test-Path $signedInstaller)) {
+ throw "SignPath did not return the signed installer: $signedInstaller"
+ }
+
+ $signature = Get-AuthenticodeSignature $signedInstaller
+ if (!$signature.SignerCertificate -or $signature.Status -eq "NotSigned") {
+ throw "SignPath returned an installer without an Authenticode signature."
+ }
+
+ Write-Host "Signer: $($signature.SignerCertificate.Subject)"
+ Write-Host "Signature status: $($signature.Status)"
+ Copy-Item $signedInstaller $destination -Force
+
- name: Build Portable CrossDesk
run: |
xmake f --CROSSDESK_VERSION=${{ env.VERSION_NUM }} --USE_CUDA=true --CROSSDESK_PORTABLE=true -y
@@ -544,6 +596,10 @@ jobs:
body: |
Binary release only. Source code is not included.
+ ## Code signing policy
+
+ Free code signing provided by [SignPath.io](https://signpath.io/), certificate by [SignPath Foundation](https://signpath.org/).
+
- name: Create or update 'latest' tag
run: |
git config user.name "github-actions[bot]"
@@ -560,6 +616,12 @@ jobs:
prerelease: false
files: release/*
generate_release_notes: false
+ body: |
+ Binary release only. Source code is not included.
+
+ ## Code signing policy
+
+ Free code signing provided by [SignPath.io](https://signpath.io/), certificate by [SignPath Foundation](https://signpath.org/).
- name: Upload artifacts to server
uses: burnett01/rsync-deployments@5.2
diff --git a/README.md b/README.md
index 0876987..9751709 100644
--- a/README.md
+++ b/README.md
@@ -10,6 +10,14 @@
[]()
[]()
+## Code signing policy
+
+Free code signing provided by [SignPath.io](https://signpath.io/), certificate by [SignPath Foundation](https://signpath.org/).
+
+- Committers and reviewers: [kunkundi](https://github.com/kunkundi)
+- Approvers: [kunkundi](https://github.com/kunkundi)
+- Privacy policy: CrossDesk will not transfer any information to other networked systems unless specifically requested by the user or the person installing or operating it.
+
[ [English](README_EN.md) / 中文 ]
PC 客户端
diff --git a/README_EN.md b/README_EN.md
index 7f9a048..07a994e 100644
--- a/README_EN.md
+++ b/README_EN.md
@@ -10,6 +10,14 @@
[]()
[]()
+## Code signing policy
+
+Free code signing provided by [SignPath.io](https://signpath.io/), certificate by [SignPath Foundation](https://signpath.org/).
+
+- Committers and reviewers: [kunkundi](https://github.com/kunkundi)
+- Approvers: [kunkundi](https://github.com/kunkundi)
+- Privacy policy: CrossDesk will not transfer any information to other networked systems unless specifically requested by the user or the person installing or operating it.
+
[ [中文](README.md) / English ]
PC Client
diff --git a/scripts/windows/crossdesk.rc b/scripts/windows/crossdesk.rc
index 2783240..7f07aee 100644
--- a/scripts/windows/crossdesk.rc
+++ b/scripts/windows/crossdesk.rc
@@ -9,3 +9,8 @@ CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "crossdesk_debug.manifest"
#else
CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "crossdesk.manifest"
#endif
+
+#define CROSSDESK_FILE_DESCRIPTION "CrossDesk"
+#define CROSSDESK_ORIGINAL_FILENAME "CrossDesk.exe"
+
+#include "version_info.rcinc"
diff --git a/scripts/windows/crossdesk_portable.rc b/scripts/windows/crossdesk_portable.rc
index a391fb5..1fe77f5 100644
--- a/scripts/windows/crossdesk_portable.rc
+++ b/scripts/windows/crossdesk_portable.rc
@@ -6,3 +6,8 @@ IDI_ICON1 ICON "..\\..\\icons\\windows\\crossdesk.ico"
#define RT_MANIFEST 24
CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "crossdesk_portable.manifest"
+
+#define CROSSDESK_FILE_DESCRIPTION "CrossDesk Portable"
+#define CROSSDESK_ORIGINAL_FILENAME "CrossDesk.exe"
+
+#include "version_info.rcinc"
diff --git a/scripts/windows/crossdesk_service.rc b/scripts/windows/crossdesk_service.rc
new file mode 100644
index 0000000..8fd8e20
--- /dev/null
+++ b/scripts/windows/crossdesk_service.rc
@@ -0,0 +1,4 @@
+#define CROSSDESK_FILE_DESCRIPTION "CrossDesk Service"
+#define CROSSDESK_ORIGINAL_FILENAME "crossdesk_service.exe"
+
+#include "version_info.rcinc"
diff --git a/scripts/windows/crossdesk_session_helper.rc b/scripts/windows/crossdesk_session_helper.rc
new file mode 100644
index 0000000..524798b
--- /dev/null
+++ b/scripts/windows/crossdesk_session_helper.rc
@@ -0,0 +1,18 @@
+// Session helper icon and manifest resources.
+IDI_ICON1 ICON "..\\..\\icons\\windows\\crossdesk.ico"
+
+#define CREATEPROCESS_MANIFEST_RESOURCE_ID 1
+#define RT_MANIFEST 24
+
+#ifdef CROSSDESK_PORTABLE
+CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "crossdesk_portable.manifest"
+#elif defined(CROSSDESK_DEBUG)
+CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "crossdesk_debug.manifest"
+#else
+CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "crossdesk.manifest"
+#endif
+
+#define CROSSDESK_FILE_DESCRIPTION "CrossDesk Session Helper"
+#define CROSSDESK_ORIGINAL_FILENAME "crossdesk_session_helper.exe"
+
+#include "version_info.rcinc"
diff --git a/scripts/windows/nsis_script.nsi b/scripts/windows/nsis_script.nsi
index 335e42c..ad8af8f 100644
--- a/scripts/windows/nsis_script.nsi
+++ b/scripts/windows/nsis_script.nsi
@@ -4,6 +4,7 @@
; Installer initial constants
!define PRODUCT_NAME "CrossDesk"
!define PRODUCT_VERSION "${VERSION}"
+!define PRODUCT_VERSION_NUMERIC "${VERSION_NUMERIC}"
!define PRODUCT_PUBLISHER "CrossDesk"
!define PRODUCT_WEB_SITE "https://www.crossdesk.cn/"
!define APP_NAME "CrossDesk"
@@ -41,6 +42,14 @@ RequestExecutionLevel admin
Name "${PRODUCT_NAME} ${PRODUCT_VERSION}"
OutFile "crossdesk-win-x64-${PRODUCT_VERSION}.exe"
+VIProductVersion "${PRODUCT_VERSION_NUMERIC}"
+VIAddVersionKey /LANG=2052 "CompanyName" "CrossDesk"
+VIAddVersionKey /LANG=2052 "FileDescription" "CrossDesk Installer"
+VIAddVersionKey /LANG=2052 "FileVersion" "${PRODUCT_VERSION}"
+VIAddVersionKey /LANG=2052 "LegalCopyright" "Copyright (C) CrossDesk contributors"
+VIAddVersionKey /LANG=2052 "OriginalFilename" "crossdesk-win-x64-${PRODUCT_VERSION}.exe"
+VIAddVersionKey /LANG=2052 "ProductName" "${PRODUCT_NAME}"
+VIAddVersionKey /LANG=2052 "ProductVersion" "${PRODUCT_VERSION}"
InstallDir "$PROGRAMFILES\CrossDesk"
InstallDirRegKey HKCU "Software\${PRODUCT_NAME}" "InstallDir"
ShowInstDetails show
diff --git a/scripts/windows/pkg_x64.ps1 b/scripts/windows/pkg_x64.ps1
index 83fc30f..b700a79 100644
--- a/scripts/windows/pkg_x64.ps1
+++ b/scripts/windows/pkg_x64.ps1
@@ -26,12 +26,40 @@ function Normalize-AppVersion {
return $InputVersion
}
+function Convert-To-WindowsVersion {
+ param(
+ [Parameter(Mandatory = $true)]
+ [string]$InputVersion
+ )
+
+ $body = $InputVersion -replace '^v', ''
+ $baseMatch = [regex]::Match($body, '^[0-9]+(?:\.[0-9]+){0,3}')
+ if (!$baseMatch.Success) {
+ return "0.0.0.0"
+ }
+
+ $parts = [System.Collections.Generic.List[int]]::new()
+ foreach ($part in $baseMatch.Value.Split('.')) {
+ $value = [int]$part
+ if ($value -gt 65535) {
+ $value = 0
+ }
+ $parts.Add($value)
+ }
+ while ($parts.Count -lt 4) {
+ $parts.Add(0)
+ }
+
+ return ($parts -join '.')
+}
+
$normalizedVersion = Normalize-AppVersion -InputVersion $Version
+$windowsVersion = Convert-To-WindowsVersion -InputVersion $normalizedVersion
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
Push-Location $scriptDir
try {
- & makensis "/DVERSION=$normalizedVersion" "nsis_script.nsi"
+ & makensis "/DVERSION=$normalizedVersion" "/DVERSION_NUMERIC=$windowsVersion" "nsis_script.nsi"
if ($LASTEXITCODE -ne 0) {
exit $LASTEXITCODE
}
diff --git a/scripts/windows/signpath-installer.xml b/scripts/windows/signpath-installer.xml
new file mode 100644
index 0000000..51d62c7
--- /dev/null
+++ b/scripts/windows/signpath-installer.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
diff --git a/scripts/windows/version_info.rcinc b/scripts/windows/version_info.rcinc
new file mode 100644
index 0000000..ed642ca
--- /dev/null
+++ b/scripts/windows/version_info.rcinc
@@ -0,0 +1,54 @@
+#include
+
+#ifndef CROSSDESK_VERSION_STRING
+#define CROSSDESK_VERSION_STRING "0.0.0"
+#endif
+
+#ifndef CROSSDESK_VERSION_NUMERIC
+#define CROSSDESK_VERSION_NUMERIC 0,0,0,0
+#endif
+
+#ifndef CROSSDESK_FILE_DESCRIPTION
+#define CROSSDESK_FILE_DESCRIPTION "CrossDesk"
+#endif
+
+#ifndef CROSSDESK_ORIGINAL_FILENAME
+#define CROSSDESK_ORIGINAL_FILENAME "CrossDesk.exe"
+#endif
+
+#ifndef CROSSDESK_FILE_TYPE
+#define CROSSDESK_FILE_TYPE VFT_APP
+#endif
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION CROSSDESK_VERSION_NUMERIC
+ PRODUCTVERSION CROSSDESK_VERSION_NUMERIC
+ FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+#ifdef CROSSDESK_DEBUG
+ FILEFLAGS VS_FF_DEBUG
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS VOS_NT_WINDOWS32
+ FILETYPE CROSSDESK_FILE_TYPE
+ FILESUBTYPE VFT2_UNKNOWN
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904B0"
+ BEGIN
+ VALUE "CompanyName", "CrossDesk\0"
+ VALUE "FileDescription", CROSSDESK_FILE_DESCRIPTION "\0"
+ VALUE "FileVersion", CROSSDESK_VERSION_STRING "\0"
+ VALUE "InternalName", CROSSDESK_ORIGINAL_FILENAME "\0"
+ VALUE "LegalCopyright", "Copyright (C) CrossDesk contributors\0"
+ VALUE "OriginalFilename", CROSSDESK_ORIGINAL_FILENAME "\0"
+ VALUE "ProductName", "CrossDesk\0"
+ VALUE "ProductVersion", CROSSDESK_VERSION_STRING "\0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x0409, 1200
+ END
+END
diff --git a/scripts/windows/wgc_plugin.rc b/scripts/windows/wgc_plugin.rc
new file mode 100644
index 0000000..76bb866
--- /dev/null
+++ b/scripts/windows/wgc_plugin.rc
@@ -0,0 +1,5 @@
+#define CROSSDESK_FILE_DESCRIPTION "CrossDesk Windows Graphics Capture Plugin"
+#define CROSSDESK_ORIGINAL_FILENAME "wgc_plugin.dll"
+#define CROSSDESK_FILE_TYPE VFT_DLL
+
+#include "version_info.rcinc"
diff --git a/tests/windows_manifest_resource_test.cpp b/tests/windows_manifest_resource_test.cpp
index d914db9..8d3ce91 100644
--- a/tests/windows_manifest_resource_test.cpp
+++ b/tests/windows_manifest_resource_test.cpp
@@ -84,6 +84,14 @@ int main() {
const std::string rc = ReadFile(repo_root / "scripts/windows/crossdesk.rc");
const std::string portable_rc =
ReadFile(repo_root / "scripts/windows/crossdesk_portable.rc");
+ const std::string service_rc =
+ ReadFile(repo_root / "scripts/windows/crossdesk_service.rc");
+ const std::string session_helper_rc =
+ ReadFile(repo_root / "scripts/windows/crossdesk_session_helper.rc");
+ const std::string wgc_plugin_rc =
+ ReadFile(repo_root / "scripts/windows/wgc_plugin.rc");
+ const std::string version_info =
+ ReadFile(repo_root / "scripts/windows/version_info.rcinc");
const std::string manifest =
ReadFile(repo_root / "scripts/windows/crossdesk.manifest");
const std::string debug_manifest =
@@ -100,8 +108,31 @@ int main() {
ok &= ExpectContains("crossdesk_portable.rc", portable_rc,
"crossdesk_portable.manifest");
ok &= ExpectContains("crossdesk_portable.rc", portable_rc, "RT_MANIFEST");
+ ok &= ExpectContains("crossdesk.rc", rc, "version_info.rcinc");
+ ok &= ExpectContains("crossdesk_portable.rc", portable_rc,
+ "version_info.rcinc");
+ ok &= ExpectContains("crossdesk_service.rc", service_rc,
+ "crossdesk_service.exe");
+ ok &= ExpectContains("crossdesk_session_helper.rc", session_helper_rc,
+ "crossdesk_session_helper.exe");
+ ok &= ExpectContains("crossdesk_session_helper.rc", session_helper_rc,
+ "CROSSDESK_PORTABLE");
+ ok &= ExpectContains("crossdesk_session_helper.rc", session_helper_rc,
+ "crossdesk_portable.manifest");
+ ok &= ExpectContains("wgc_plugin.rc", wgc_plugin_rc, "wgc_plugin.dll");
+ ok &= ExpectContains("version_info.rcinc", version_info, "ProductName");
+ ok &= ExpectContains("version_info.rcinc", version_info,
+ "ProductVersion");
+ ok &= ExpectContains("version_info.rcinc", version_info,
+ "OriginalFilename");
ok &= ExpectContains("xmake/targets.lua", targets,
"scripts/windows/crossdesk_portable.rc");
+ ok &= ExpectContains("xmake/targets.lua", targets,
+ "scripts/windows/crossdesk_service.rc");
+ ok &= ExpectContains("xmake/targets.lua", targets,
+ "scripts/windows/crossdesk_session_helper.rc");
+ ok &= ExpectContains("xmake/targets.lua", targets,
+ "scripts/windows/wgc_plugin.rc");
ok &= ExpectContains("xmake/targets.lua", targets, "CROSSDESK_PORTABLE");
ok &= ExpectContains("crossdesk.manifest", manifest,
"level=\"requireAdministrator\"");
diff --git a/xmake/options.lua b/xmake/options.lua
index 2618795..b82b0bf 100644
--- a/xmake/options.lua
+++ b/xmake/options.lua
@@ -35,6 +35,28 @@ function setup_options_and_dependencies()
set_languages("c++17")
set_encodings("utf-8")
+ local crossdesk_version = get_config("CROSSDESK_VERSION") or "0.0.0"
+ local version_base = crossdesk_version:gsub("^v", ""):match("^(%d[%d%.]*)") or "0.0.0"
+ local version_parts = {}
+ for part in version_base:gmatch("%d+") do
+ local value = tonumber(part) or 0
+ if value > 65535 then
+ value = 0
+ end
+ table.insert(version_parts, value)
+ if #version_parts == 4 then
+ break
+ end
+ end
+ while #version_parts < 4 do
+ table.insert(version_parts, 0)
+ end
+
+ add_defines("CROSSDESK_VERSION_STRING=\"" .. crossdesk_version .. "\"")
+ if is_os("windows") then
+ add_defines("CROSSDESK_VERSION_NUMERIC=" .. table.concat(version_parts, ","))
+ end
+
-- set_policy("build.warning", true)
-- set_warnings("all", "extra")
-- add_cxxflags("/W4", "/WX")
diff --git a/xmake/targets.lua b/xmake/targets.lua
index bbfd7ac..f79edbb 100644
--- a/xmake/targets.lua
+++ b/xmake/targets.lua
@@ -297,6 +297,7 @@ function setup_targets()
add_files("src/screen_capturer/windows/screen_capturer_wgc.cpp",
"src/screen_capturer/windows/wgc_session_impl.cpp",
"src/screen_capturer/windows/wgc_plugin_entry.cpp")
+ add_files("scripts/windows/wgc_plugin.rc")
add_includedirs("src/common", "src/screen_capturer",
"src/screen_capturer/windows")
@@ -306,6 +307,7 @@ function setup_targets()
add_links("Advapi32", "Wtsapi32", "Ole32", "Userenv")
add_files("src/service/windows/main.cpp",
"src/service/windows/service_host.cpp")
+ add_files("scripts/windows/crossdesk_service.rc")
add_includedirs("src/service/windows", {public = true})
target("crossdesk_session_helper")
@@ -314,7 +316,7 @@ function setup_targets()
add_deps("rd_log", "path_manager")
add_links("Advapi32", "User32", "Wtsapi32", "Gdi32")
add_files("src/service/windows/session_helper_main.cpp")
- add_files(crossdesk_windows_resource)
+ add_files("scripts/windows/crossdesk_session_helper.rc")
add_includedirs("src/common", "src/service/windows", {public = true})
end