diff --git a/src/app/utils/updateErrors.test.ts b/src/app/utils/updateErrors.test.ts index 85574044d..780917a46 100644 --- a/src/app/utils/updateErrors.test.ts +++ b/src/app/utils/updateErrors.test.ts @@ -69,13 +69,23 @@ test('install kinds: anything unknown keeps the in-app updater', async () => { test('package installs get their package manager’s command, not an Install button', async () => { const { packageUpdateHelp, isPackageManagedError } = await import('./updateErrors'); const pacman = packageUpdateHelp('pacman')!; - // Not `pacman -U `: that also wants `.sig`, which we don't publish. - assert.equal( - pacman.command, - 'curl -LO https://code.lotusguild.org/LotusGuild/cinny-desktop/releases/download/latest/LotusChat-x86_64.pkg.tar.zst && sudo pacman -U ./LotusChat-x86_64.pkg.tar.zst', + // [cinny-desktop #36] signature, then checksum, then install, in that order; + // a local `pacman -U ./file` (not ``, which also wants `.sig`). + const steps = pacman.command!.split(' && '); + assert.equal(steps[0], 'cd "$(mktemp -d)"'); + assert.match( + steps[1], + /-fLO \S+\/LotusChat-x86_64\.pkg\.tar\.zst -fLO \S+\/SHA256SUMS\.txt -fLO \S+\/SHA256SUMS\.txt\.minisig$/, ); + assert.equal( + steps[2], + 'minisign -Vm SHA256SUMS.txt -P RWRZZdyii05/NUcz337A5SAbiZK+NPVDWuiL2mM5Jk1p/LfRmNfiZ/6l', + ); + assert.equal(steps[3], 'sha256sum -c --ignore-missing SHA256SUMS.txt'); + assert.equal(steps[4], 'sudo pacman -U ./LotusChat-x86_64.pkg.tar.zst'); assert.match(pacman.url, /LotusChat-x86_64\.pkg\.tar\.zst$/); const deb = packageUpdateHelp('deb')!; + assert.match(deb.command!, /minisign -Vm SHA256SUMS\.txt/); assert.match(deb.command!, /sudo apt install \.\/LotusChat-x86_64\.deb$/); assert.equal(packageUpdateHelp('manual')?.command, undefined); assert.equal(packageUpdateHelp('in-app'), undefined); diff --git a/src/app/utils/updateErrors.ts b/src/app/utils/updateErrors.ts index e45201e22..f3e2f5a7e 100644 --- a/src/app/utils/updateErrors.ts +++ b/src/app/utils/updateErrors.ts @@ -64,23 +64,38 @@ export const toInstallKind = (value: unknown): InstallKind => export type PackageUpdateHelp = { command?: string; url: string; download: string }; +/** The desktop updater's minisign public key (cinny-desktop tauri.conf.json). */ +export const RELEASE_MINISIGN_KEY = 'RWRZZdyii05/NUcz337A5SAbiZK+NPVDWuiL2mM5Jk1p/LfRmNfiZ/6l'; + +/** + * [cinny-desktop #36] Download a Linux package and install it only after + * checking the release's minisign-signed SHA256SUMS.txt. Runs in a fresh temp + * directory so a stale SHA256SUMS.txt can't be picked up. + */ +const verifiedInstall = (file: string, install: string): string => + [ + `cd "$(mktemp -d)"`, + `curl -fLO ${RELEASE_DOWNLOAD}/${file} -fLO ${RELEASE_DOWNLOAD}/SHA256SUMS.txt -fLO ${RELEASE_DOWNLOAD}/SHA256SUMS.txt.minisig`, + `minisign -Vm SHA256SUMS.txt -P ${RELEASE_MINISIGN_KEY}`, + `sha256sum -c --ignore-missing SHA256SUMS.txt`, + `${install} ./${file}`, + ].join(' && '); + export const packageUpdateHelp = (kind: InstallKind): PackageUpdateHelp | undefined => { if (kind === 'pacman') { - const url = `${RELEASE_DOWNLOAD}/LotusChat-x86_64.pkg.tar.zst`; - // Download first, then install the local file: `pacman -U ` also - // fetches `.sig` and fails without it (we don't sign packages), - // while a local file falls under LocalFileSigLevel (signature optional). + // Install the local file: `pacman -U ` also fetches `.sig` and + // fails without it (packages aren't signed for pacman), while a local file + // falls under LocalFileSigLevel. Integrity comes from SHA256SUMS.txt. return { - command: `curl -LO ${url} && sudo pacman -U ./LotusChat-x86_64.pkg.tar.zst`, - url, + command: verifiedInstall('LotusChat-x86_64.pkg.tar.zst', 'sudo pacman -U'), + url: `${RELEASE_DOWNLOAD}/LotusChat-x86_64.pkg.tar.zst`, download: 'Download package', }; } if (kind === 'deb') { - const url = `${RELEASE_DOWNLOAD}/LotusChat-x86_64.deb`; return { - command: `curl -LO ${url} && sudo apt install ./LotusChat-x86_64.deb`, - url, + command: verifiedInstall('LotusChat-x86_64.deb', 'sudo apt install'), + url: `${RELEASE_DOWNLOAD}/LotusChat-x86_64.deb`, download: 'Download package', }; }