Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 13 additions & 4 deletions .changeset/config.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
{
"$schema": "https://unpkg.com/@changesets/config@3.1.1/schema.json",
"changelog": ["@changesets/changelog-github", { "repo": "lightpanda-io/node-packages" }],
"changelog": [
"@changesets/changelog-github",
{
"repo": "lightpanda-io/node-packages"
}
],
"commit": true,
"fixed": [["@lightpanda/browser"]],
"fixed": [
[
"@lightpanda/browser"
]
],
"linked": [],
"access": "restricted",
"access": "public",
"baseBranch": "main",
"updateInternalDependencies": "patch",
"ignore": []
}
}
44 changes: 41 additions & 3 deletions packages/browser/src/download.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,18 @@
import { constants, chmodSync, createWriteStream, existsSync, mkdirSync } from 'node:fs'
import https from 'node:https'
import { arch, exit, platform } from 'node:process'
import { DEFAULT_CACHE_FOLDER, DEFAULT_EXECUTABLE_PATH, USER_EXECUTABLE_PATH } from './utils'
import {
DEFAULT_CACHE_FOLDER,
DEFAULT_EXECUTABLE_PATH,
GITHUB_RELEASE_DATA_URL,
USER_EXECUTABLE_PATH,
checksumFile,
} from './utils'

type GH_ASSET = {
name: string
digest: string
}

const PLATFORMS = {
darwin: {
Expand Down Expand Up @@ -66,18 +77,45 @@ export const download = async (): Promise<void> => {
return new Promise((resolve, reject) => get(url, resolve, reject))
}

const getGithubHash = async (path: string) => {
try {
const f = await fetch(path)
const data = await f.json()

const asset: GH_ASSET = data.assets.find(
(a: GH_ASSET) => a.name === `lightpanda-${platformPath}`,
)

if (asset) {
return asset.digest
}

return ''
} catch (e) {
throw new Error(e)
}
}

if (platformPath) {
if (USER_EXECUTABLE_PATH) {
console.info('$LIGHTPANDA_EXECUTABLE_PATH found, skipping binary download…')
exit(0)
}

try {
console.info('⏳ Downloading latest version of Lightpanda browser…')

console.info('⏳ Downloading latest version of Lightpanda browser…', '\n')
await downloadBinary(
`https://github.com/lightpanda-io/browser/releases/download/nightly/lightpanda-${platformPath}`,
)

console.info('🔐 Getting and comparing checksums…', '\n')
const ghChecksum = await getGithubHash(GITHUB_RELEASE_DATA_URL)
const lpChecksum = await checksumFile(DEFAULT_EXECUTABLE_PATH)

if (ghChecksum !== lpChecksum) {
throw new Error("🚫 Checksums don't match!")
}

chmodSync(DEFAULT_EXECUTABLE_PATH, constants.S_IRWXU)

console.info('✅ Done!')
Expand Down
26 changes: 26 additions & 0 deletions packages/browser/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import crypto, { type BinaryToTextEncoding } from 'node:crypto'
import fs from 'node:fs'
import os from 'node:os'

export const DEFAULT_CACHE_FOLDER = `${os.homedir()}/.cache/lightpanda-node`
Expand All @@ -21,6 +24,9 @@ export const BINARY_NAME = 'lightpanda'
export const USER_EXECUTABLE_PATH = process.env.LIGHTPANDA_EXECUTABLE_PATH
export const DEFAULT_EXECUTABLE_PATH = `${DEFAULT_CACHE_FOLDER}/${BINARY_NAME}`

export const GITHUB_RELEASE_DATA_URL =
'https://api.github.com/repos/lightpanda-io/browser/releases/tags/nightly'

/**
* Validate a URL structure
* @param {string} url URL to validate
Expand Down Expand Up @@ -61,3 +67,23 @@ export const validatePort = (port: number): void => {
export const getExecutablePath = () => {
return USER_EXECUTABLE_PATH ?? DEFAULT_EXECUTABLE_PATH
}

/**
* Get checksum from file
*/
export const checksumFile = (
filePath: string,
algorithm = 'sha256',
encoding: BinaryToTextEncoding = 'hex',
) => {
return new Promise((resolve, reject) => {
fs.readFile(filePath, (err, data) => {
if (err) {
reject(err)
}

const hash = crypto.createHash(algorithm).update(data).digest(encoding)
resolve(`${algorithm}:${hash}`)
})
})
}