electron-builder.config.cjs copied CLOUDFLARE_R2_PUBLIC_URL into the generic publish provider after only trimming a trailing slash. That URL ends up in app-update.yml, which every installed client trusts for the life of the build, so an http://, credentialed, or query-bearing var would have shipped silently. update-feed.cjs (the feed contract) now owns feedBaseUrl(): https only, no credentials/query/fragment, spelled as the URL parser re-serializes it (trailing slash tolerated, like the Python side). Both the Windows and macOS publish entries read the validated value.
41 lines
1.6 KiB
JavaScript
41 lines
1.6 KiB
JavaScript
'use strict'
|
|
|
|
// Historical native URLs are a compatibility layout, not a channel registry.
|
|
/** @param {string} channel @param {boolean} light */
|
|
function darwinFeed(channel, light = false) {
|
|
if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(channel) || channel.length > 32 ||
|
|
/^(con|prn|aux|nul|com[1-9]|lpt[1-9])$/.test(channel)) {
|
|
throw new TypeError('Invalid channel name')
|
|
}
|
|
return {
|
|
directory: `releases/darwin/${light ? 'light/' : ''}${channel}`,
|
|
channel,
|
|
fileName: `${channel}-mac.yml`,
|
|
allowPrerelease: channel !== 'stable'
|
|
}
|
|
}
|
|
|
|
// The feed origin is baked into app-update.yml and trusted by every
|
|
// installed client for the life of the build, so the CI var must be a
|
|
// canonical https base: no credentials, query, or fragment, spelled exactly
|
|
// as the URL parser re-serializes it (a trailing slash is tolerated, as the
|
|
// Python release scripts do). Anything else is a misconfigured release
|
|
// environment and must fail the build, not ship.
|
|
/** @param {string | undefined} raw @returns {string | undefined} */
|
|
function feedBaseUrl(raw) {
|
|
if (raw === undefined || raw === '') return undefined
|
|
let url
|
|
try {
|
|
url = new URL(raw)
|
|
} catch {
|
|
throw new TypeError(`CLOUDFLARE_R2_PUBLIC_URL is not a URL: ${raw}`)
|
|
}
|
|
const canonical = url.origin + url.pathname.replace(/\/+$/, '')
|
|
if (url.protocol !== 'https:' || url.username || url.password || url.search || url.hash || canonical !== raw.replace(/\/+$/, '')) {
|
|
throw new TypeError(`CLOUDFLARE_R2_PUBLIC_URL must be a canonical https base (got ${raw}, expected ${canonical})`)
|
|
}
|
|
return canonical
|
|
}
|
|
|
|
module.exports = { darwinFeed, feedBaseUrl }
|