Add sha256sum check for update downloads

This commit is contained in:
2025-11-02 22:36:06 -07:00
parent e8b630ee37
commit 48a7ed545f
6 changed files with 46 additions and 8 deletions

View File

@@ -18,7 +18,7 @@
"@eslint/eslintrc": "3.3.1", "@eslint/eslintrc": "3.3.1",
"@tailwindcss/postcss": "4.1.16", "@tailwindcss/postcss": "4.1.16",
"@tauri-apps/cli": "2.9.2", "@tauri-apps/cli": "2.9.2",
"@types/node": "24.9.2", "@types/node": "24.10.0",
"@types/react": "19.2.2", "@types/react": "19.2.2",
"@types/react-dom": "19.2.2", "@types/react-dom": "19.2.2",
"eslint": "9.39.0", "eslint": "9.39.0",
@@ -257,7 +257,7 @@
"@types/json5": ["@types/json5@0.0.29", "", {}, "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ=="], "@types/json5": ["@types/json5@0.0.29", "", {}, "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ=="],
"@types/node": ["@types/node@24.9.2", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-uWN8YqxXxqFMX2RqGOrumsKeti4LlmIMIyV0lgut4jx7KQBcBiW6vkDtIBvHnHIquwNfJhk8v2OtmO8zXWHfPA=="], "@types/node": ["@types/node@24.10.0", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-qzQZRBqkFsYyaSWXuEHc2WR9c0a0CXwiE5FWUvn7ZM+vdy1uZLfCunD38UzhuB7YN/J11ndbDBcTmOdxJo9Q7A=="],
"@types/react": ["@types/react@19.2.2", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA=="], "@types/react": ["@types/react@19.2.2", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA=="],
@@ -381,7 +381,7 @@
"callsites": ["callsites@3.1.0", "", {}, "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="], "callsites": ["callsites@3.1.0", "", {}, "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="],
"caniuse-lite": ["caniuse-lite@1.0.30001752", "", {}, "sha512-vKUk7beoukxE47P5gcVNKkDRzXdVofotshHwfR9vmpeFKxmI5PBpgOMC18LUJUA/DvJ70Y7RveasIBraqsyO/g=="], "caniuse-lite": ["caniuse-lite@1.0.30001753", "", {}, "sha512-Bj5H35MD/ebaOV4iDLqPEtiliTN29qkGtEHCwawWn4cYm+bPJM2NsaP30vtZcnERClMzp52J4+aw2UNbK4o+zw=="],
"chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], "chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="],

View File

@@ -24,7 +24,7 @@
"devDependencies": { "devDependencies": {
"@tauri-apps/cli": "2.9.2", "@tauri-apps/cli": "2.9.2",
"typescript": "5.9.3", "typescript": "5.9.3",
"@types/node": "24.9.2", "@types/node": "24.10.0",
"@types/react": "19.2.2", "@types/react": "19.2.2",
"@types/react-dom": "19.2.2", "@types/react-dom": "19.2.2",
"@tailwindcss/postcss": "4.1.16", "@tailwindcss/postcss": "4.1.16",

View File

@@ -22,6 +22,7 @@ tauri-plugin-os = "2.3.2"
reqwest = { version = "0.12.24", default-features = false, features = ["stream", "rustls-tls"] } reqwest = { version = "0.12.24", default-features = false, features = ["stream", "rustls-tls"] }
tauri-plugin-opener = "2.5.2" tauri-plugin-opener = "2.5.2"
tauri-plugin-dialog = "2.4.2" tauri-plugin-dialog = "2.4.2"
sha2 = "0.10.9"
[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies] [target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies]
tauri-plugin-single-instance = "2.3.6" tauri-plugin-single-instance = "2.3.6"

View File

@@ -1,3 +1,4 @@
use sha2::{Digest, Sha256};
use std::{ use std::{
fs::{File, create_dir_all}, fs::{File, create_dir_all},
io::{BufReader, copy}, io::{BufReader, copy},
@@ -41,6 +42,13 @@ async fn unzip_to_dir(zip_path: PathBuf, out_dir: PathBuf) -> String {
} }
} }
fn get_sha256_hash(data: &[u8]) -> String {
let mut hasher = Sha256::new();
hasher.update(data);
let hash = hasher.finalize();
format!("{:x}", hash)
}
#[tauri::command] #[tauri::command]
async fn check_latest_ver(app: AppHandle, version: String) -> String { async fn check_latest_ver(app: AppHandle, version: String) -> String {
let updates_path = app.path().app_local_data_dir().unwrap().join("updates"); let updates_path = app.path().app_local_data_dir().unwrap().join("updates");
@@ -55,7 +63,7 @@ async fn check_latest_ver(app: AppHandle, version: String) -> String {
} }
#[tauri::command] #[tauri::command]
async fn download(app: AppHandle, url: String, name: String) -> String { async fn download(app: AppHandle, url: String, name: String, hash: String) -> String {
let client = reqwest::Client::new(); let client = reqwest::Client::new();
let resp = match client.get(&url).send().await { let resp = match client.get(&url).send().await {
Ok(r) => r, Ok(r) => r,
@@ -66,6 +74,11 @@ async fn download(app: AppHandle, url: String, name: String) -> String {
Err(_) => return "-1".to_string(), Err(_) => return "-1".to_string(),
}; };
let download_hash = get_sha256_hash(&bytes);
if hash != download_hash {
return "-2".to_string();
}
let downloads_path = app.path().app_local_data_dir().unwrap().join("downloads"); let downloads_path = app.path().app_local_data_dir().unwrap().join("downloads");
let updates_path = app.path().app_local_data_dir().unwrap().join("updates"); let updates_path = app.path().app_local_data_dir().unwrap().join("updates");

View File

@@ -66,11 +66,15 @@ export default function Home () {
if (!launcherUpdateData) return if (!launcherUpdateData) return
const downloadResult = await invoke('download', { const downloadResult = await invoke('download', {
url: getDownloadLink(launcherUpdateData), url: getDownloadLink(launcherUpdateData),
name: launcherLatestRequest.data name: launcherLatestRequest.data,
hash: getDownloadHash(launcherUpdateData)
}) })
if (downloadResult !== '1') { if (downloadResult == '-1') {
setState('Failed. Check internet connection.') setState('Failed. Check internet connection.')
return return
} else if (downloadResult == '-2') {
setState('File integrity check failed.')
return
} }
setState('Starting...') setState('Starting...')
} }
@@ -101,6 +105,26 @@ export default function Home () {
return undefined return undefined
} }
function getDownloadHash (version: LauncherUpdate): string | undefined {
const p = platform()
const a = arch()
const findUrl = (plat: string) => {
const i = version.platforms.indexOf(plat)
return i >= 0 ? version.sha256sums[i] : undefined
}
if (p === 'windows') {
if (a === 'x86_64') return findUrl('windows-x64')
if (a === 'aarch64') return findUrl('windows-arm64')
} else if (p === 'macos') {
if (a === 'x86_64') return findUrl('macos-intel')
if (a === 'aarch64') return findUrl('macos-silicon')
} else if (p === 'linux') return findUrl(p)
return undefined
}
return ( return (
<> <>
<div className='absolute left-1/2 top-[20%] -translate-x-1/2 flex flex-col items-center'> <div className='absolute left-1/2 top-[20%] -translate-x-1/2 flex flex-col items-center'>

View File

@@ -3,5 +3,5 @@ export interface LauncherUpdate {
releaseDate: number releaseDate: number
downloadUrls: string[] downloadUrls: string[]
platforms: string[] platforms: string[]
executables: string[] sha256sums: string[]
} }