Update web installer for fastboot.js updates

Some of the API and paths have changed, so this needs to be updated
accordingly. The most prominent change is the removal of BlobStore and
downloading support from fastboot.js, because a fastboot library should
not be responsible for downloading files.
This commit is contained in:
Danny Lin 2021-01-27 16:54:13 -08:00 committed by Daniel Micay
parent 3c2c76dfdf
commit 890abfdaff
4 changed files with 132 additions and 27 deletions

View File

@ -7,7 +7,7 @@ export PATH="$PWD/node_modules/.bin:$PATH"
rm -rf static_tmp rm -rf static_tmp
cp -a static static_tmp cp -a static static_tmp
rm -rf static_tmp/js/fastboot/{!(dist),dist/!(fastboot.min.js|libs)} rm -rf static_tmp/js/fastboot/{!(dist),dist/!(fastboot.min.mjs|libs)}
for file in static_tmp/**/*.@(json|webmanifest); do for file in static_tmp/**/*.@(json|webmanifest); do
json_reformat -m < "$file" | sponge "$file" json_reformat -m < "$file" | sponge "$file"

View File

@ -26,8 +26,8 @@
<link rel="stylesheet" href="/grapheneos.css?29"/> <link rel="stylesheet" href="/grapheneos.css?29"/>
<link rel="manifest" href="/manifest.webmanifest"/> <link rel="manifest" href="/manifest.webmanifest"/>
<link rel="license" href="/LICENSE.txt"/> <link rel="license" href="/LICENSE.txt"/>
<script type="module" src="/js/fastboot/dist/fastboot.min.js?0"></script> <script type="module" src="/js/fastboot/dist/fastboot.min.mjs?0"></script>
<script type="module" src="/js/web-install.js?4"></script> <script type="module" src="/js/web-install.js?5"></script>
</head> </head>
<body> <body>
<header> <header>

View File

@ -1,11 +1,98 @@
// @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt MIT // @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt MIT
import { FastbootDevice, FactoryImages } from "./fastboot/dist/fastboot.min.js?0"; import * as fastboot from "./fastboot/dist/fastboot.min.mjs?0";
const RELEASES_URL = "https://releases.grapheneos.org"; const RELEASES_URL = "https://releases.grapheneos.org";
let device = new FastbootDevice(); const CACHE_DB_NAME = "BlobStore";
let lastReleaseZip = null; const CACHE_DB_VERSION = 1;
class BlobStore {
constructor() {
this.db = null;
}
async _wrapReq(request, onUpgrade = null) {
return new Promise((resolve, reject) => {
request.onsuccess = () => {
resolve(request.result);
};
request.oncomplete = () => {
resolve(request.result);
};
request.onerror = (event) => {
reject(event);
};
if (onUpgrade !== null) {
request.onupgradeneeded = onUpgrade;
}
});
}
async init() {
if (this.db === null) {
this.db = await this._wrapReq(
indexedDB.open(CACHE_DB_NAME, CACHE_DB_VERSION),
(event) => {
let db = event.target.result;
db.createObjectStore("files", { keyPath: "name" });
/* no index needed for such a small database */
}
);
}
}
async saveFile(name, blob) {
this.db.transaction(["files"], "readwrite").objectStore("files").add({
name: name,
blob: blob,
});
}
async loadFile(name) {
try {
let obj = await this._wrapReq(
this.db.transaction("files").objectStore("files").get(name)
);
return obj.blob;
} catch (error) {
return null;
}
}
async close() {
this.db.close();
}
/**
* Downloads the file from the given URL and saves it to this BlobStore.
*
* @param {string} url - URL of the file to download.
* @returns {blob} Blob containing the downloaded data.
*/
async download(url) {
let filename = url.split("/").pop();
let blob = await this.loadFile(filename);
if (blob === null) {
console.log(`Downloading ${url}`);
let resp = await fetch(new Request(url));
blob = await resp.blob();
console.log("File downloaded, saving...");
await this.saveFile(filename, blob);
console.log("File saved");
} else {
console.log(
`Loaded ${filename} from blob store, skipping download`
);
}
return blob;
}
}
let device = new fastboot.FastbootDevice();
let blobStore = new BlobStore();
async function ensureConnected(setProgress) { async function ensureConnected(setProgress) {
console.log(device.device); console.log(device.device);
@ -23,36 +110,50 @@ async function unlockBootloader(setProgress) {
return "Bootloader unlocked."; return "Bootloader unlocked.";
} }
async function downloadRelease(setProgress) { async function getLatestRelease() {
await ensureConnected(setProgress);
setProgress("Getting device model...");
let product = await device.getVariable("product"); let product = await device.getVariable("product");
setProgress("Finding latest release...");
let metadataResp = await fetch(`${RELEASES_URL}/${product}-stable`); let metadataResp = await fetch(`${RELEASES_URL}/${product}-stable`);
let metadata = await metadataResp.text(); let metadata = await metadataResp.text();
let releaseId = metadata.split(" ")[0]; let releaseId = metadata.split(" ")[0];
return `${product}-factory-${releaseId}.zip`;
}
async function downloadRelease(setProgress) {
await ensureConnected(setProgress);
setProgress("Finding latest release...");
let latestZip = await getLatestRelease();
// Download and cache the zip as a blob // Download and cache the zip as a blob
setProgress(`Downloading ${releaseId} release for ${product}...`); setProgress(`Downloading ${latestZip}...`);
lastReleaseZip = `${product}-factory-${releaseId}.zip`; await blobStore.init();
await FactoryImages.downloadZip(`${RELEASES_URL}/${lastReleaseZip}`); await blobStore.download(`${RELEASES_URL}/${latestZip}`);
return `Downloaded ${releaseId} release for ${product}.`; return `Downloaded ${latestZip} release.`;
} }
async function flashRelease(setProgress) { async function flashRelease(setProgress) {
await ensureConnected(setProgress); await ensureConnected(setProgress);
// Need to do this again because the user may not have clicked download if
// it was cached
setProgress("Finding latest release...");
let latestZip = await getLatestRelease();
await blobStore.init();
let blob = await blobStore.loadFile(latestZip);
if (blob === null) {
throw new Error("You need to download a release first!");
}
setProgress("Flashing release..."); setProgress("Flashing release...");
await FactoryImages.flashZip(device, lastReleaseZip, (action, partition) => { await fastboot.FactoryImages.flashZip(device, blob, true, (action, item) => {
let userPartition = partition == "avb_custom_key" ? "verified boot key" : partition; let userAction = fastboot.FactoryImages.USER_ACTION_MAP[action];
if (action == "unpack") { let userItem = item === "avb_custom_key" ? "verified boot key" : item;
setProgress(`Unpacking image: ${userPartition}`); setProgress(`${userAction} ${userItem}...`);
} else {
setProgress(`Flashing image: ${userPartition}`);
}
}); });
return `Flashed ${lastReleaseZip} to device.`;
return `Flashed ${latestZip} to device.`;
} }
async function lockBootloader(setProgress) { async function lockBootloader(setProgress) {
@ -83,9 +184,13 @@ function addButtonHook(id, callback) {
}; };
} }
FactoryImages.configureZip({ // This doesn't really hurt, and because this page is exclusively for web install,
// we can tolerate extra logging in the console in case something goes wrong.
fastboot.setDebugMode(true);
fastboot.FactoryImages.configureZip({
workerScripts: { workerScripts: {
inflate: ["/js/fastboot/dist/libs/z-worker-pako.js", "pako_inflate.min.js"], inflate: ["/js/fastboot/dist/vendor/z-worker-pako.js", "pako_inflate.min.js"],
}, },
}); });

View File

@ -7,13 +7,13 @@ export PATH="$PWD/node_modules/.bin:$PATH"
rm -rf static_tmp rm -rf static_tmp
cp -a static static_tmp cp -a static static_tmp
rm -rf static_tmp/js/fastboot/{!(dist),dist/!(fastboot.min.js|libs)} rm -rf static_tmp/js/fastboot/{!(dist),dist/!(fastboot.min.mjs|libs)}
for file in static_tmp/**/*.@(json|webmanifest); do for file in static_tmp/**/*.@(json|webmanifest); do
json_verify < "$file" >/dev/null json_verify < "$file" >/dev/null
done done
xmllint --noout static_tmp/**/*.@(html|svg|xml) xmllint --noout static_tmp/**/*.@(html|svg|xml)
eslint static_tmp/**/!(fastboot.min|z-worker-pako|pako_inflate.min).js eslint static_tmp/**/!(fastboot.min.m|z-worker-pako.|pako_inflate.min.)js
stylelint static_tmp/**/*.css stylelint static_tmp/**/*.css
validatornu --Werror --also-check-css --also-check-svg static_tmp/**/*.@(css|html|svg) validatornu --Werror --also-check-css --also-check-svg static_tmp/**/*.@(css|html|svg)