Skip to content

Commit 3cc08bd

Browse files
authored
Chore/#7 Checksum binary (#8)
* fix: make changeset public * feat: add checksum verification * chore: add const for gh url
1 parent 67042a6 commit 3cc08bd

File tree

3 files changed

+80
-7
lines changed

3 files changed

+80
-7
lines changed

.changeset/config.json

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,20 @@
11
{
22
"$schema": "https://unpkg.com/@changesets/config@3.1.1/schema.json",
3-
"changelog": ["@changesets/changelog-github", { "repo": "lightpanda-io/node-packages" }],
3+
"changelog": [
4+
"@changesets/changelog-github",
5+
{
6+
"repo": "lightpanda-io/node-packages"
7+
}
8+
],
49
"commit": true,
5-
"fixed": [["@lightpanda/browser"]],
10+
"fixed": [
11+
[
12+
"@lightpanda/browser"
13+
]
14+
],
615
"linked": [],
7-
"access": "restricted",
16+
"access": "public",
817
"baseBranch": "main",
918
"updateInternalDependencies": "patch",
1019
"ignore": []
11-
}
20+
}

packages/browser/src/download.ts

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,18 @@
1616
import { constants, chmodSync, createWriteStream, existsSync, mkdirSync } from 'node:fs'
1717
import https from 'node:https'
1818
import { arch, exit, platform } from 'node:process'
19-
import { DEFAULT_CACHE_FOLDER, DEFAULT_EXECUTABLE_PATH, USER_EXECUTABLE_PATH } from './utils'
19+
import {
20+
DEFAULT_CACHE_FOLDER,
21+
DEFAULT_EXECUTABLE_PATH,
22+
GITHUB_RELEASE_DATA_URL,
23+
USER_EXECUTABLE_PATH,
24+
checksumFile,
25+
} from './utils'
26+
27+
type GH_ASSET = {
28+
name: string
29+
digest: string
30+
}
2031

2132
const PLATFORMS = {
2233
darwin: {
@@ -66,18 +77,45 @@ export const download = async (): Promise<void> => {
6677
return new Promise((resolve, reject) => get(url, resolve, reject))
6778
}
6879

80+
const getGithubHash = async (path: string) => {
81+
try {
82+
const f = await fetch(path)
83+
const data = await f.json()
84+
85+
const asset: GH_ASSET = data.assets.find(
86+
(a: GH_ASSET) => a.name === `lightpanda-${platformPath}`,
87+
)
88+
89+
if (asset) {
90+
return asset.digest
91+
}
92+
93+
return ''
94+
} catch (e) {
95+
throw new Error(e)
96+
}
97+
}
98+
6999
if (platformPath) {
70100
if (USER_EXECUTABLE_PATH) {
71101
console.info('$LIGHTPANDA_EXECUTABLE_PATH found, skipping binary download…')
72102
exit(0)
73103
}
74104

75105
try {
76-
console.info('⏳ Downloading latest version of Lightpanda browser…')
77-
106+
console.info('⏳ Downloading latest version of Lightpanda browser…', '\n')
78107
await downloadBinary(
79108
`https://github.com/lightpanda-io/browser/releases/download/nightly/lightpanda-${platformPath}`,
80109
)
110+
111+
console.info('🔐 Getting and comparing checksums…', '\n')
112+
const ghChecksum = await getGithubHash(GITHUB_RELEASE_DATA_URL)
113+
const lpChecksum = await checksumFile(DEFAULT_EXECUTABLE_PATH)
114+
115+
if (ghChecksum !== lpChecksum) {
116+
throw new Error("🚫 Checksums don't match!")
117+
}
118+
81119
chmodSync(DEFAULT_EXECUTABLE_PATH, constants.S_IRWXU)
82120

83121
console.info('✅ Done!')

packages/browser/src/utils.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
*/
16+
17+
import crypto, { type BinaryToTextEncoding } from 'node:crypto'
18+
import fs from 'node:fs'
1619
import os from 'node:os'
1720

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

27+
export const GITHUB_RELEASE_DATA_URL =
28+
'https://api.github.com/repos/lightpanda-io/browser/releases/tags/nightly'
29+
2430
/**
2531
* Validate a URL structure
2632
* @param {string} url URL to validate
@@ -61,3 +67,23 @@ export const validatePort = (port: number): void => {
6167
export const getExecutablePath = () => {
6268
return USER_EXECUTABLE_PATH ?? DEFAULT_EXECUTABLE_PATH
6369
}
70+
71+
/**
72+
* Get checksum from file
73+
*/
74+
export const checksumFile = (
75+
filePath: string,
76+
algorithm = 'sha256',
77+
encoding: BinaryToTextEncoding = 'hex',
78+
) => {
79+
return new Promise((resolve, reject) => {
80+
fs.readFile(filePath, (err, data) => {
81+
if (err) {
82+
reject(err)
83+
}
84+
85+
const hash = crypto.createHash(algorithm).update(data).digest(encoding)
86+
resolve(`${algorithm}:${hash}`)
87+
})
88+
})
89+
}

0 commit comments

Comments
 (0)