support downloading and unpacking GrapheneOS images
This commit is contained in:
parent
22256ea40b
commit
1d00936a4a
3 changed files with 39 additions and 9 deletions
|
@ -388,7 +388,11 @@ async function unpackFactoryImage(factoryImagePath: string, image: DeviceImage,
|
||||||
// There's a TOCTOU race (file is accessed after check), but it affects all other generated files too.
|
// There's a TOCTOU race (file is accessed after check), but it affects all other generated files too.
|
||||||
// Fixing it for this particular case is not worth the complexity increase
|
// Fixing it for this particular case is not worth the complexity increase
|
||||||
} else {
|
} else {
|
||||||
throw new Error(`SHA-256 mismatch for '${image.fileName}': expected ${image.sha256} got ${sha256}`)
|
if (image.skipSha256Check) {
|
||||||
|
console.warn(`skipping SHA-256 check for ${image.fileName}, SHA-256: ${sha256}`)
|
||||||
|
} else {
|
||||||
|
throw new Error(`SHA-256 mismatch for '${image.fileName}': expected ${image.sha256} got ${sha256}`)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let fd = await fs.open(factoryImagePath, 'r')
|
let fd = await fs.open(factoryImagePath, 'r')
|
||||||
|
@ -400,9 +404,15 @@ async function unpackFactoryImage(factoryImagePath: string, image: DeviceImage,
|
||||||
let entry: yauzl.Entry = entryP
|
let entry: yauzl.Entry = entryP
|
||||||
let entryName = entry.filename
|
let entryName = entry.filename
|
||||||
|
|
||||||
let isInnerZip =
|
let isInnerZip = false
|
||||||
entryName.includes(`-${image.buildId.toLowerCase()}/image-${image.deviceConfig.device.name}`) &&
|
|
||||||
entryName.endsWith(`-${image.buildId.toLowerCase()}.zip`)
|
let deviceName = image.deviceConfig.device.name
|
||||||
|
if (image.isGrapheneOS) {
|
||||||
|
isInnerZip = entryName.includes(`/image-${deviceName}-`) && entryName.endsWith('.zip')
|
||||||
|
} else {
|
||||||
|
isInnerZip = entryName.includes(`-${image.buildId.toLowerCase()}/image-${deviceName}`) &&
|
||||||
|
entryName.endsWith(`-${image.buildId.toLowerCase()}.zip`)
|
||||||
|
}
|
||||||
|
|
||||||
if (!isInnerZip) {
|
if (!isInnerZip) {
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -5,6 +5,8 @@ import { DeviceConfig, getDeviceBuildId } from '../config/device'
|
||||||
import { IMAGE_DOWNLOAD_DIR } from '../config/paths'
|
import { IMAGE_DOWNLOAD_DIR } from '../config/paths'
|
||||||
import { BuildIndex, DEFAULT_BASE_DOWNLOAD_URL, ImageType } from './build-index'
|
import { BuildIndex, DEFAULT_BASE_DOWNLOAD_URL, ImageType } from './build-index'
|
||||||
|
|
||||||
|
const GRAPHENEOS_PSEUDO_BUILD_ID_PREFIX = 'gos-'
|
||||||
|
|
||||||
export class DeviceImage {
|
export class DeviceImage {
|
||||||
constructor(
|
constructor(
|
||||||
readonly deviceConfig: DeviceConfig,
|
readonly deviceConfig: DeviceConfig,
|
||||||
|
@ -13,8 +15,9 @@ export class DeviceImage {
|
||||||
readonly fileName: string,
|
readonly fileName: string,
|
||||||
readonly sha256: string,
|
readonly sha256: string,
|
||||||
readonly url: string,
|
readonly url: string,
|
||||||
) {
|
readonly skipSha256Check: boolean,
|
||||||
}
|
readonly isGrapheneOS: boolean,
|
||||||
|
) {}
|
||||||
|
|
||||||
getPath() {
|
getPath() {
|
||||||
return path.join(IMAGE_DOWNLOAD_DIR, this.fileName)
|
return path.join(IMAGE_DOWNLOAD_DIR, this.fileName)
|
||||||
|
@ -32,6 +35,15 @@ export class DeviceImage {
|
||||||
let deviceBuildId = getDeviceBuildId(deviceConfig, buildId)
|
let deviceBuildId = getDeviceBuildId(deviceConfig, buildId)
|
||||||
let buildProps = index.get(deviceBuildId)
|
let buildProps = index.get(deviceBuildId)
|
||||||
if (buildProps === undefined) {
|
if (buildProps === undefined) {
|
||||||
|
if (buildId.startsWith(GRAPHENEOS_PSEUDO_BUILD_ID_PREFIX)) {
|
||||||
|
let fileName = deviceConfig.device.name + '-factory-' +
|
||||||
|
buildId.substring(GRAPHENEOS_PSEUDO_BUILD_ID_PREFIX.length) + '.zip'
|
||||||
|
|
||||||
|
let url = 'https://releases.grapheneos.org/' + fileName
|
||||||
|
|
||||||
|
return new DeviceImage(deviceConfig, type, buildId, fileName, 'no sha256', url, true, true)
|
||||||
|
}
|
||||||
|
|
||||||
throw new Error(`no images for '${deviceBuildId}'`)
|
throw new Error(`no images for '${deviceBuildId}'`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,7 +66,7 @@ export class DeviceImage {
|
||||||
fileName = ending
|
fileName = ending
|
||||||
url = DEFAULT_BASE_DOWNLOAD_URL + fileName
|
url = DEFAULT_BASE_DOWNLOAD_URL + fileName
|
||||||
}
|
}
|
||||||
return new DeviceImage(deviceConfig, type, buildId, fileName, sha256, url)
|
return new DeviceImage(deviceConfig, type, buildId, fileName, sha256, url, false, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
static async getMissing(arr: DeviceImage[]) {
|
static async getMissing(arr: DeviceImage[]) {
|
||||||
|
|
|
@ -70,13 +70,21 @@ async function downloadImage(image: DeviceImage, outDir: string) {
|
||||||
|
|
||||||
let sha256Digest: string = sha256.digest('hex')
|
let sha256Digest: string = sha256.digest('hex')
|
||||||
console.log('SHA-256: ' + sha256Digest)
|
console.log('SHA-256: ' + sha256Digest)
|
||||||
assert(sha256Digest === image.sha256, 'SHA256 mismatch, expected ' + image.sha256)
|
if (image.skipSha256Check) {
|
||||||
|
console.warn('skipping SHA-256 check for ' + completeOutFile)
|
||||||
|
} else {
|
||||||
|
assert(sha256Digest === image.sha256, 'SHA256 mismatch, expected ' + image.sha256)
|
||||||
|
}
|
||||||
|
|
||||||
await fs.rename(tmpOutFile, completeOutFile)
|
await fs.rename(tmpOutFile, completeOutFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
function logTermsAndConditionsNotice(images: DeviceImage[]) {
|
function logTermsAndConditionsNotice(images: DeviceImage[]) {
|
||||||
if (images.filter(i => i.type === ImageType.Factory || i.type === ImageType.Ota).length == 0) {
|
if (
|
||||||
|
images.filter(i => {
|
||||||
|
return !i.isGrapheneOS && (i.type === ImageType.Factory || i.type === ImageType.Ota)
|
||||||
|
}).length == 0
|
||||||
|
) {
|
||||||
// vendor images show T&C notice themselves as part of unpacking
|
// vendor images show T&C notice themselves as part of unpacking
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue