The Windows signing docs still told users to import a certificate we no longer publish #238
@@ -70,12 +70,18 @@
|
||||
# latest stable tag via scripts/ci/pf-version.ps1, run number climbs monotonically).
|
||||
# Both arches share the version; artifacts are arch-suffixed (..._x64.msix / ..._arm64.msix).
|
||||
#
|
||||
# Signing (clients/windows/packaging/pack-msix.ps1): if the MSIX_CERT_PFX_B64 / MSIX_CERT_PASSWORD
|
||||
# Actions secrets are set (a real or shared code-signing .pfx whose subject DN == Publisher), the
|
||||
# package is signed with them. Otherwise an ephemeral self-signed cert is generated and its public
|
||||
# .cer is published next to the .msix (users import it to Trusted People before install).
|
||||
# Signing (clients/windows/packaging/pack-msix.ps1), first match wins:
|
||||
# 1. Azure Artifact Signing — what this workflow always takes, since the AZURE_CODESIGNING_*
|
||||
# endpoint/account/profile are literals below and only the AZURE_TENANT_ID / AZURE_CLIENT_ID /
|
||||
# AZURE_CLIENT_SECRET secrets are needed. Publicly trusted, so NO .cer is emitted or published
|
||||
# and users import nothing. NOTE the Publisher DN is the Azure profile's verified subject, and
|
||||
# MSIX identity is name + publisher: moving to it changed the package identity, so installs
|
||||
# predating it need an uninstall, not an upgrade.
|
||||
# 2. MSIX_CERT_PFX_B64 / MSIX_CERT_PASSWORD — the older self-signed .pfx, kept as a fallback.
|
||||
# 3. an ephemeral self-signed cert. Modes 2 and 3 DO emit a .cer next to the .msix, which users
|
||||
# would have to import into Trusted People before Windows will install the package.
|
||||
#
|
||||
# That fallback is for canary/CI ONLY. On a v* tag the pack script FAILS CLOSED — a missing secret
|
||||
# Modes 2 and 3 are for canary/CI ONLY. On a v* tag the pack script FAILS CLOSED — a missing secret
|
||||
# aborts the build instead of quietly shipping a release signed by a per-build throwaway cert that
|
||||
# no one can pin. Nothing to opt into here: the script reads GITHUB_REF itself.
|
||||
name: windows-client
|
||||
|
||||
@@ -12,7 +12,8 @@ x64 Windows runner — `x86_64-pc-windows-msvc` builds natively, `aarch64-pc-win
|
||||
cross-compiled (the x64 MSVC toolset ships the ARM64 cross compiler; since M10 nothing in the
|
||||
package links FFmpeg, so neither arch needs a per-arch `FFMPEG_DIR` tree staged on the runner —
|
||||
one less thing the ARM64 leg can be missing). Artifacts are arch-suffixed
|
||||
(`..._x64.msix` / `..._arm64.msix`, each with its matching `.cer`); `pack-msix.ps1 -Arch x64|arm64`
|
||||
(`..._x64.msix` / `..._arm64.msix`, plus a matching `.cer` only in the fallback signing modes 2 and 3
|
||||
— Azure signing emits none); `pack-msix.ps1 -Arch x64|arm64`
|
||||
stamps the manifest `ProcessorArchitecture` and names the output. See
|
||||
[`windows-client.yml`](../../../.gitea/workflows/windows-client.yml) for the cross-build rationale.
|
||||
|
||||
@@ -52,7 +53,8 @@ low-level input hooks, WASAPI and SDL3.
|
||||
MSIX requires a strictly 4-part numeric version. The workflow computes:
|
||||
- `vX.Y.Z` tag → `X.Y.Z.0` (THE release; any `-rc`/`+meta` suffix is dropped for MSIX). Published to
|
||||
the stable `latest/` alias and attached to the unified Gitea Release.
|
||||
- `main` push / `workflow_dispatch` → `0.3.<run_number>.0` (canary, climbs by run number; `canary/` alias).
|
||||
- `main` push / `workflow_dispatch` → `X.<Y+1>.<run_number>.0` (canary — the minor *after* the latest
|
||||
`v*` tag, per `scripts/ci/pf-version.ps1`, climbing by run number; `canary/` alias).
|
||||
|
||||
## Signing & install
|
||||
|
||||
|
||||
@@ -103,29 +103,24 @@ See [packaging/flatpak](https://git.unom.io/unom/punktfunk/src/branch/main/packa
|
||||
|
||||
## Windows
|
||||
|
||||
The Windows client ships as a **signed MSIX** in the package registry. Builds use a self-signed
|
||||
certificate, so you import that certificate once before Windows will install the package.
|
||||
The Windows client ships as a **signed MSIX** in the package registry, signed with a publicly
|
||||
trusted certificate — so there is nothing to import and nothing to trust by hand. Download, install.
|
||||
|
||||
1. Download the package and its certificate. Each channel keeps one fixed URL, so these two lines
|
||||
always fetch the current build — in PowerShell:
|
||||
1. Download the package. Each channel keeps one fixed URL, so this line always fetches the current
|
||||
build — in PowerShell:
|
||||
|
||||
```powershell
|
||||
curl.exe -LO https://git.unom.io/api/packages/unom/generic/punktfunk-client-windows/latest/punktfunk-client-windows_x64.msix
|
||||
curl.exe -LO https://git.unom.io/api/packages/unom/generic/punktfunk-client-windows/latest/punktfunk-client-windows_x64.cer
|
||||
```
|
||||
|
||||
Swap `_x64` for `_arm64` on an Arm device, and `latest` for `canary` to track `main`. The same
|
||||
two files are attached to every [release](https://git.unom.io/unom/punktfunk/releases), and every
|
||||
file is attached to every [release](https://git.unom.io/unom/punktfunk/releases), and every
|
||||
build is also kept under its own version on the
|
||||
[packages page](https://git.unom.io/unom/-/packages) (generic group, `punktfunk-client-windows`).
|
||||
2. **Trust the publisher certificate**, then install. The MSIX won't install until the certificate is
|
||||
trusted — but it's the **same certificate for every release**, so this is genuinely one-time and
|
||||
later updates need nothing. In an **admin** PowerShell:
|
||||
2. Install it:
|
||||
|
||||
```powershell
|
||||
# use the _arm64 files instead on an Arm device
|
||||
Import-Certificate -FilePath .\punktfunk-client-windows_x64.cer `
|
||||
-CertStoreLocation Cert:\LocalMachine\TrustedPeople
|
||||
# use the _arm64 file instead on an Arm device
|
||||
Add-AppxPackage .\punktfunk-client-windows_x64.msix
|
||||
```
|
||||
|
||||
@@ -133,6 +128,10 @@ certificate, so you import that certificate once before Windows will install the
|
||||
[Windows App Runtime 2.x](https://learn.microsoft.com/windows/apps/windows-app-sdk/downloads)
|
||||
(the MSIX depends on `Microsoft.WindowsAppRuntime.2`), then re-run `Add-AppxPackage`.
|
||||
|
||||
Install from a signed-in desktop session. Over a remote, non-interactive session (SSH, an RMM
|
||||
tool) `Add-AppxPackage` can fail with `0x80070005` when the Windows App Runtime it depends on is
|
||||
in use and Windows can't restart the apps holding it.
|
||||
|
||||
3. Launch **Punktfunk** from the Start menu and pick your host. The package also adds a second
|
||||
entry, **Punktfunk Console** — the same client as a controller-driven fullscreen interface for a
|
||||
TV or HTPC — and the headless `punktfunk` command on your PATH.
|
||||
@@ -223,7 +222,7 @@ but keeping them close is the least surprising. (Updating the **host** is its ow
|
||||
| **Linux Flatpak** | `flatpak update --user io.unom.Punktfunk` — **without `sudo`** (see the [Flatpak section](#linux-desktop-flatpak)) |
|
||||
| **Linux apt / dnf / pacman** | your normal `sudo apt upgrade` / `sudo dnf upgrade` / `sudo pacman -Syu`, or the app's own updater below |
|
||||
| **Fedora Atomic (layered)** | `rpm-ostree upgrade` on its own is not enough — see the note below the table |
|
||||
| **Windows MSIX** | no self-update — download the newer `.msix` as in [Windows](#windows) and re-run `Add-AppxPackage`. The certificate is the same every release, so you don't import it again |
|
||||
| **Windows MSIX** | no self-update — download the newer `.msix` as in [Windows](#windows) and re-run `Add-AppxPackage`. Coming from **0.28.1 or earlier**, see the note below the table |
|
||||
| **macOS `.dmg`** | download the newer `Punktfunk-<version>.dmg` and drag it over the copy in Applications |
|
||||
| **iOS / iPadOS / tvOS** | TestFlight updates it |
|
||||
| **Android** | Google Play updates it; if you sideloaded, download the APK again and install over it |
|
||||
@@ -244,6 +243,20 @@ systemctl reboot
|
||||
The client's own updater below runs exactly that dance for you, if you'd rather not remember it. (A
|
||||
layered **host** has the same trap — [Updating](/docs/updating) covers it.)
|
||||
|
||||
**Windows, coming from 0.28.1 or earlier — uninstall first.** Those builds were signed with our own
|
||||
self-signed certificate. The move to a publicly trusted one changes the package's *publisher*, and an
|
||||
MSIX's identity is its name **plus** its publisher — so Windows treats the new package as a different
|
||||
app rather than an update, and installing it leaves you with two **Punktfunk** entries. Remove the
|
||||
old one first, then install the new `.msix` as above:
|
||||
|
||||
```powershell
|
||||
Get-AppxPackage *Punktfunk* | Remove-AppxPackage
|
||||
```
|
||||
|
||||
This is one-time; releases after that upgrade in place. Note that a packaged app's settings live
|
||||
*inside* its package, so removing the old one also removes this client's identity and its paired
|
||||
hosts — expect to [pair](/docs/pairing) again once. Nothing on the host side is affected.
|
||||
|
||||
### The Linux client can update itself
|
||||
|
||||
The native Linux client checks its own channel and can apply the update in place, so you don't have
|
||||
|
||||
@@ -70,22 +70,22 @@ everything the installer puts on the machine, its optional tasks, the console pa
|
||||
This is also the path for **canary** builds, which winget doesn't carry — see
|
||||
[Release Channels](/docs/channels) for that download.
|
||||
|
||||
> **About the Unknown Publisher prompt.** The installer is signed with a self-signed certificate, so
|
||||
> Windows warns before it runs — accepting the prompt is enough, nothing else is required. The winget
|
||||
> route is no different: it downloads and runs that same installer. If you'd
|
||||
> rather silence it, the matching **`punktfunk-host-windows_<ver>.cer`** is published next to the
|
||||
> installer, and it's the **same certificate for every release**, so this is one-time. A self-signed
|
||||
> certificate is its own root, so it has to go in both stores. In an **admin** PowerShell:
|
||||
> **About signing.** The installer is signed with a publicly trusted certificate, so Windows shows
|
||||
> the publisher by name at the UAC prompt — there is no Unknown Publisher warning and nothing to
|
||||
> import. The winget route is no different: it downloads and runs that same installer.
|
||||
>
|
||||
> ```powershell
|
||||
> Import-Certificate -FilePath .\punktfunk-host-windows_<ver>.cer `
|
||||
> -CertStoreLocation Cert:\LocalMachine\Root
|
||||
> Import-Certificate -FilePath .\punktfunk-host-windows_<ver>.cer `
|
||||
> -CertStoreLocation Cert:\LocalMachine\TrustedPublisher
|
||||
> ```
|
||||
> SmartScreen is a separate mechanism that builds reputation per publisher, so shortly after a new
|
||||
> signing certificate starts being used it can still show *"Windows protected your PC"* on the first
|
||||
> downloads — **More info → Run anyway**. It settles as installs accumulate.
|
||||
>
|
||||
> This is a different certificate from the one the bundled **drivers** are signed with — the
|
||||
> installer imports that one for you.
|
||||
> The bundled **drivers** are a separate matter — they carry their own certificate, and the installer
|
||||
> imports that one for you. [Windows Host](/docs/windows-host#about-the-signatures) has the detail.
|
||||
>
|
||||
> Releases **0.28.1 and earlier** were signed with our own self-signed certificate, and older docs
|
||||
> told you to import it. Nothing needs it any more: if you imported
|
||||
> `punktfunk-host-windows_<ver>.cer` back then, you can remove it from `Cert:\LocalMachine\Root` and
|
||||
> `Cert:\LocalMachine\TrustedPublisher` (look for the certificate issued to **unom**, thumbprint
|
||||
> `CD1EFDEEEC9743AFC38F56C5AF30C5A3009BE941`).
|
||||
|
||||
## NixOS
|
||||
|
||||
|
||||
@@ -227,9 +227,12 @@ Three things are left on purpose:
|
||||
component other apps may be using, so the Punktfunk uninstaller never touches it. Remove it
|
||||
with its own uninstaller — `VBCABLE_Setup_x64.exe -u -h` — or the **VB-Audio Virtual Cable**
|
||||
entry in Installed apps.
|
||||
- **The publisher certificate**, if you imported it by hand to silence the Unknown Publisher prompt.
|
||||
Remove it in `certlm.msc` under **Trusted Publishers** and **Trusted Root Certification
|
||||
Authorities**. (This is *not* the driver certificate above, which the uninstaller does remove.)
|
||||
- **The old publisher certificate**, if you imported it by hand to silence the Unknown Publisher
|
||||
prompt on 0.28.1 or earlier. Releases since then are signed by a publicly trusted CA and never
|
||||
needed it, so it is safe to drop: remove the certificate issued to **unom** (thumbprint
|
||||
`CD1EFDEEEC9743AFC38F56C5AF30C5A3009BE941`) in `certlm.msc` under **Trusted Publishers** and
|
||||
**Trusted Root Certification Authorities**. (This is *not* the driver certificate above, which the
|
||||
uninstaller does remove.)
|
||||
|
||||
If you registered the winget source, drop it too — in an **admin** PowerShell, the same as
|
||||
registering it:
|
||||
|
||||
@@ -94,12 +94,14 @@ are `winget upgrade unom.PunktfunkHost` and removal is `winget uninstall unom.Pu
|
||||
|
||||
### About the signatures
|
||||
|
||||
Punktfunk signs with its own certificates rather than a publicly trusted one, so Windows warns about
|
||||
an unknown publisher before setup runs. Accepting the prompt is enough. To silence it for good, the
|
||||
matching **`punktfunk-host-windows_<ver>.cer`** is published next to the installer and it is the
|
||||
same certificate for every release — the one-time import is in
|
||||
[Install → Windows](/docs/install#windows). This applies to the winget path too: winget downloads
|
||||
and runs that same installer.
|
||||
Setup, and the Punktfunk executables it installs, are signed with a **publicly trusted** certificate,
|
||||
so UAC names the publisher rather than warning about an unknown one, and there is nothing for you to
|
||||
import. This applies to the winget path too: winget downloads and runs that same installer. (The
|
||||
bundled third-party pieces keep whatever their own vendors shipped.)
|
||||
|
||||
Releases **0.28.1 and earlier** were signed with our own self-signed certificate, and the docs then
|
||||
asked you to import `punktfunk-host-windows_<ver>.cer`. Current builds no longer produce or need it —
|
||||
[Install → Windows](/docs/install#windows) shows how to remove it if you imported one.
|
||||
|
||||
The bundled drivers carry a **second, separate** self-signed certificate (`CN=punktfunk-driver`,
|
||||
SHA-1 thumbprint `4B8493E7CD565758D335F8F4F05C5A7261A13E02`). The installer adds it to the machine's
|
||||
@@ -114,12 +116,22 @@ punktfunk-host-setup-<ver>.exe /VERYSILENT /SUPPRESSMSGBOXES /NORESTART /SP-
|
||||
|
||||
Keep `/SUPPRESSMSGBOXES`: without it an unattended run can stop on a message box nobody can see.
|
||||
|
||||
A silent run takes the same defaults as the wizard, so add or drop individual options with Inno's
|
||||
`/MERGETASKS` — a bare name adds a task, a `!` prefix removes one. `/MERGETASKS="gamestream"` turns
|
||||
on Moonlight compatibility; `/MERGETASKS="!trayicon"` skips the status icon. The task names are
|
||||
`installdriver`, `installgamepad`, `installaudiocable`, `installhdrlayer`, `gamestream`,
|
||||
A silent **first** install takes the same defaults as the wizard, so add or drop individual options
|
||||
with Inno's `/MERGETASKS` — a bare name adds a task, a `!` prefix removes one.
|
||||
`/MERGETASKS="gamestream"` turns on Moonlight compatibility; `/MERGETASKS="!trayicon"` skips the
|
||||
status icon. The task names are `installdriver`, `installgamepad`, `installhdrlayer`, `gamestream`,
|
||||
`allowpublicfw`, `startservice` and `trayicon`.
|
||||
|
||||
An **upgrade** is different: it reuses the choices the previous install recorded, not the defaults
|
||||
above. That is usually what you want, but it means anything you once declined stays declined — and
|
||||
if that includes `installgamepad`, the gamepad drivers are never updated alongside the host, which
|
||||
surfaces later as a virtual controller games stop seeing. To force the full set on an upgrade, name
|
||||
them (`/MERGETASKS` merges with the remembered set rather than replacing it):
|
||||
|
||||
```powershell
|
||||
punktfunk-host-setup-<ver>.exe /VERYSILENT /SUPPRESSMSGBOXES /NORESTART /SP- /MERGETASKS="installdriver,installgamepad,installhdrlayer,startservice"
|
||||
```
|
||||
|
||||
Two things to know before you script it:
|
||||
|
||||
- Setup **aborts with a non-zero exit code** if another Moonlight-compatible host — Sunshine, Apollo,
|
||||
|
||||
@@ -303,7 +303,8 @@ pwsh -File packaging\windows\pack-host-installer.ps1 -Version 0.0.0-dev -TargetD
|
||||
|
||||
Push a `vX.Y.Z` tag — one tag releases every platform (see
|
||||
[Release Channels](https://punktfunk.unom.io/docs/channels)). The workflow builds, signs, and
|
||||
publishes `punktfunk-host-setup-X.Y.Z.exe` + the public `.cer`, refreshes the stable `latest/`
|
||||
publishes `punktfunk-host-setup-X.Y.Z.exe` (no `.cer` — Azure signing is publicly trusted, and mode 2
|
||||
or 3 would be needed to emit one), refreshes the stable `latest/`
|
||||
alias, and attaches the installer to the unified Gitea Release. Main pushes publish rolling
|
||||
`<next-minor>.<run>` **canary** builds (base derived from the latest stable tag by
|
||||
`scripts/ci/pf-version.ps1`) to the `canary/` alias.
|
||||
|
||||
Reference in New Issue
Block a user