Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

minor: allow passing custom assets to start SB protected CM4 #324

Merged
merged 3 commits into from
Jun 13, 2024
Merged
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
2 changes: 1 addition & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
module.exports = {
extends: ["./node_modules/@balena/lint/config/.eslintrc.js"],
root: true,
ignorePatterns: ["node_modules/", "dist/", "examples/"],
ignorePatterns: ["node_modules/", "dist/", "tests/", "examples"],
rules: {
"@typescript-eslint/no-floating-promises": "off",
"no-bitwise": "off",
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
build
*~
node_modules
yalc.lock
.yalc
6 changes: 4 additions & 2 deletions examples/scanner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,14 @@ import { platform } from 'os';

import { scanner } from '../lib/';

async function main() {
const bootImageDir = String(process.argv.slice(2));

async function main(usbBootExtraFolder?: string) {
const adapters: scanner.adapters.Adapter[] = [
new scanner.adapters.BlockDeviceAdapter({
includeSystemDrives: () => true,
}),
new scanner.adapters.UsbbootDeviceAdapter(),
new scanner.adapters.UsbbootDeviceAdapter(bootImageDir),
];
if (platform() === 'win32') {
if (scanner.adapters.DriverlessDeviceAdapter !== undefined) {
Expand Down
55 changes: 50 additions & 5 deletions examples/usbboot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,61 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { argv } from 'process';

/**
* Unlocking with secureboot
*
* If you need to expose the internal storage of a cm4 with secureboot, you need to provide a signed boot-image to set the device in MSD mode.
alexgg marked this conversation as resolved.
Show resolved Hide resolved
* Pass the bootImageDir flag with the path to the folder containing the signed boot-image.
*/

import ProgressBar = require('progress');

import { scanner, sourceDestination } from '../lib/';

import { pipeSourceToDestinationsWithProgressBar } from './utils';

// Parse command line arguments
const args = process.argv.slice(2); // removes 'node' and the script name from the args
const flags: any = {};

args.forEach((arg: string, index: number) => {
// Check if the argument is a flag in the format --flag=value
if (arg.startsWith('--')) {
const key: string = arg.substring(2);
const value: string = args[index + 1];
flags[key] = value;
}
});

if (!flags.source) {
console.log("No source has been provided, won't try to flash anything");
}

if (flags.bootImageDir !== '') {
console.log(`Using external directory ${flags['bootImageDir']}`);
}

if (flags.help) {
console.log(
'Usage: ts-node usbboot.js --bootImageDir <bootImageDir> --source <image>',
);
console.log(
'Beware, `source` image will be flashed to all USBboot devices, so make sure you know what you are doing',
);
console.log(
'To expose the internal mass storage device on a locked device, set the bootImageDir to the path of a directory containing a signed boot.img and config.txt.',
);
process.exit(0);
}

async function main() {
const bootImageDir = flags.bootImageDir;
const adapters: scanner.adapters.Adapter[] = [
new scanner.adapters.BlockDeviceAdapter({
includeSystemDrives: () => false,
}),
new scanner.adapters.UsbbootDeviceAdapter(),
new scanner.adapters.UsbbootDeviceAdapter(bootImageDir),
];
const deviceScanner = new scanner.Scanner(adapters);
console.log('Waiting for one compute module');
Expand Down Expand Up @@ -74,6 +116,8 @@ async function main() {
drive instanceof sourceDestination.BlockDevice &&
drive.description === 'Compute Module'
) {
drive.oWrite = true;
drive.oDirect = true;
resolve(drive);
deviceScanner.removeListener('attach', onAttach);
}
Expand All @@ -84,11 +128,12 @@ async function main() {
);
deviceScanner.stop();

if (argv.length >= 3) {
console.log(`Writing image ${argv[2]}`);
if (flags.source) {
console.log(JSON.stringify(dest));
console.log(`Writing image ${flags.source} to ${dest.path}`);
const source: sourceDestination.SourceDestination =
new sourceDestination.File({
path: argv[2],
path: flags.source,
});
void pipeSourceToDestinationsWithProgressBar({
source,
Expand Down
4 changes: 2 additions & 2 deletions lib/scanner/adapters/usbboot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ export class UsbbootDeviceAdapter extends Adapter {
private drives: Map<UsbbootDevice, UsbbootDrive> = new Map();
private scanner?: UsbbootScannerType;

constructor() {
constructor(usbBootExtraDir?: string | undefined) {
super();
const rpiUsbboot = getRaspberrypiUsbboot();
if (rpiUsbboot !== undefined) {
this.scanner = new rpiUsbboot.UsbbootScanner();
this.scanner = new rpiUsbboot.UsbbootScanner(usbBootExtraDir);
this.scanner.on('attach', this.onAttach.bind(this));
this.scanner.on('detach', this.onDetach.bind(this));
this.scanner.on('ready', this.emit.bind(this, 'ready'));
Expand Down
27 changes: 15 additions & 12 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@
"lzma-native": "^8.0.6",
"minimatch": "^9.0.3",
"mountutils": "^1.3.20",
"node-raspberrypi-usbboot": "1.0.7",
"node-raspberrypi-usbboot": "1.1.0",
"outdent": "^0.8.0",
"partitioninfo": "^6.0.2",
"rwmutex": "^1.0.0",
Expand Down Expand Up @@ -106,7 +106,7 @@
"yargs": "^17.7.2"
},
"engines": {
"node": ">=18"
"node": ">=18 <22"
},
"versionist": {
"publishedAt": "2024-04-26T12:35:55.545Z"
Expand Down
5 changes: 2 additions & 3 deletions tests/tester.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,9 +137,8 @@ export async function testImageNoIt(
assert(canCreateSparseReadStream);
const sourceSparseStream = await innerSource.createSparseReadStream();

const sourceSparseStreamBuffer = await sparseStreamToBuffer(
sourceSparseStream,
);
const sourceSparseStreamBuffer =
await sparseStreamToBuffer(sourceSparseStream);
expect(sourceSparseStreamBuffer.length).to.be.at.most(compareToData.length);
expect(sourceSparseStreamBuffer).to.deep.equal(
compareToData.slice(0, sourceSparseStreamBuffer.length),
Expand Down
21 changes: 8 additions & 13 deletions tests/utils.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,14 +66,11 @@ describe('utils', function () {
describe('BalenaS3SourceBase', function () {
describe('isESRVersion', function () {
it('should return false for non-ESR versions following the original scheme', function () {
[
'2.7.8.dev',
'2.7.8.prod',
'2.80.3.0.dev',
'2.80.3.0.prod',
].forEach((v) => {
expect(BalenaS3SourceBase.isESRVersion(v)).to.be.false;
});
['2.7.8.dev', '2.7.8.prod', '2.80.3.0.dev', '2.80.3.0.prod'].forEach(
(v) => {
expect(BalenaS3SourceBase.isESRVersion(v)).to.be.false;
},
);
});
aethernet marked this conversation as resolved.
Show resolved Hide resolved

it('should return false for unified non-ESR versions', function () {
Expand All @@ -83,11 +80,9 @@ describe('utils', function () {
});

it('should return true for ESR versions following the original scheme', function () {
['2020.04.0.prod', '2021.10.1.dev', '2021.10.1.prod'].forEach(
(v) => {
expect(BalenaS3SourceBase.isESRVersion(v)).to.be.true;
},
);
['2020.04.0.prod', '2021.10.1.dev', '2021.10.1.prod'].forEach((v) => {
expect(BalenaS3SourceBase.isESRVersion(v)).to.be.true;
});
aethernet marked this conversation as resolved.
Show resolved Hide resolved
});

it('should return true for unified ESR versions', function () {
Expand Down
Loading