mirror of
https://github.com/kilyabin/psysonic.git
synced 2026-07-21 22:15:40 +00:00
50ac1b8284
Co-authored-by: kilyabin <kilyabin@users.noreply.github.com> Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
91 lines
2.9 KiB
JavaScript
91 lines
2.9 KiB
JavaScript
#!/usr/bin/env node
|
|
// Generates latest.json for the Tauri updater from a GitHub release.
|
|
// Reads .sig files uploaded by tauri-action, assembles the manifest, writes latest.json.
|
|
//
|
|
// Required env vars: VERSION, GITHUB_TOKEN
|
|
// Usage: node scripts/generate-update-manifest.js
|
|
|
|
const { execSync } = require('child_process');
|
|
const fs = require('fs');
|
|
|
|
const VERSION = process.env.VERSION;
|
|
const REPO = 'Psychotoxical/psysonic';
|
|
const TAG = `app-v${VERSION}`;
|
|
|
|
if (!VERSION) {
|
|
console.error('VERSION env var required');
|
|
process.exit(1);
|
|
}
|
|
|
|
// Platform → update bundle filename (produced by tauri-action with updater plugin)
|
|
const PLATFORM_FILES = {
|
|
'darwin-aarch64': `Psysonic_aarch64.app.tar.gz`,
|
|
'darwin-x86_64': `Psysonic_x64.app.tar.gz`,
|
|
'windows-x86_64': `Psysonic_${VERSION}_x64-setup.nsis.zip`,
|
|
};
|
|
|
|
const platforms = {};
|
|
|
|
// A real minisign .sig file is multi-line and ~200+ chars.
|
|
// A public key (RWTxxx... single line, ~56 chars) must never appear here.
|
|
function validateSignature(sig, platform, sigFile) {
|
|
// Public keys start with RWT and are a single short base64 token
|
|
if (/^RWT[A-Za-z0-9+/]{10,}={0,2}$/.test(sig)) {
|
|
throw new Error(
|
|
`${platform}: .sig file "${sigFile}" contains a PUBLIC KEY instead of a signature.\n` +
|
|
` Got: ${sig}\n` +
|
|
` The TAURI_SIGNING_PUBLIC_KEY env var must never be used as the signature value.\n` +
|
|
` Ensure the signing step correctly writes the .sig file from the private key.`
|
|
);
|
|
}
|
|
if (sig.length < 80) {
|
|
throw new Error(
|
|
`${platform}: .sig file "${sigFile}" looks too short (${sig.length} chars) to be a valid signature.`
|
|
);
|
|
}
|
|
}
|
|
|
|
for (const [platform, filename] of Object.entries(PLATFORM_FILES)) {
|
|
const sigFile = `${filename}.sig`;
|
|
try {
|
|
execSync(
|
|
`gh release download "${TAG}" --repo "${REPO}" -p "${sigFile}" --clobber`,
|
|
{ stdio: 'pipe' }
|
|
);
|
|
const signature = fs.readFileSync(sigFile, 'utf8').trim();
|
|
validateSignature(signature, platform, sigFile);
|
|
const url = `https://github.com/${REPO}/releases/download/${TAG}/${filename}`;
|
|
platforms[platform] = { signature, url };
|
|
console.log(`✓ ${platform}`);
|
|
} catch (e) {
|
|
console.warn(`⚠ Skipping ${platform}: ${e.message}`);
|
|
}
|
|
}
|
|
|
|
if (Object.keys(platforms).length === 0) {
|
|
console.error('No platforms found — aborting manifest generation');
|
|
process.exit(1);
|
|
}
|
|
|
|
// Pull release notes from GitHub
|
|
let notes = '';
|
|
try {
|
|
const raw = execSync(
|
|
`gh release view "${TAG}" --repo "${REPO}" --json body`,
|
|
{ stdio: 'pipe' }
|
|
).toString();
|
|
notes = JSON.parse(raw).body ?? '';
|
|
} catch {
|
|
console.warn('Could not fetch release notes');
|
|
}
|
|
|
|
const manifest = {
|
|
version: VERSION,
|
|
notes,
|
|
pub_date: new Date().toISOString(),
|
|
platforms,
|
|
};
|
|
|
|
fs.writeFileSync('latest.json', JSON.stringify(manifest, null, 2));
|
|
console.log(`\nWrote latest.json for v${VERSION} with platforms: ${Object.keys(platforms).join(', ')}`);
|