Skip to content

Commit

Permalink
Feature request: add ability to rekey/sign apps
Browse files Browse the repository at this point in the history
Added support for the following commands:

1. Rekey Device: Rekey specified device based on the signing password ("brightscript.remoteControl.signingPassword") and package file ("brightscript.remoteControl.signedPackagePath") provided.

2. Create Package: This will present user a list of available launch configs to choose from. Once selected it will create a .zip file and .pkg file based on the config and will save them  to the ${workspacefolder}/out

3. Rekey Device and Create Package: This will first rekey device and then create package for the selected launch config
  • Loading branch information
fumer-fubotv committed Oct 13, 2023
1 parent 323c4f1 commit ab5629e
Show file tree
Hide file tree
Showing 2 changed files with 128 additions and 0 deletions.
15 changes: 15 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2771,6 +2771,21 @@
"category": "BrighterScript",
"icon": "./images/icons/inspect-active.svg"
},
{
"command": "extension.brightscript.rekeyDevice",
"title": "Rekey Device",
"category": "BrighterScript"
},
{
"command": "extension.brightscript.createPackage",
"title": "Create Package",
"category": "BrighterScript"
},
{
"command": "extension.brightscript.rekeyAndPackage",
"title": "Rekey Device and Create Package",
"category": "BrighterScript"
},
{
"command": "extension.brightscript.captureScreenshot",
"title": "Capture Screenshot",
Expand Down
113 changes: 113 additions & 0 deletions src/BrightScriptCommands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import { util as rokuDebugUtil } from 'roku-debug/dist/util';
import type { RemoteControlManager, RemoteControlModeInitiator } from './managers/RemoteControlManager';
import type { WhatsNewManager } from './managers/WhatsNewManager';
import type { ActiveDeviceManager } from './ActiveDeviceManager';
import * as rokuDeploy from 'roku-deploy';
import * as path from 'path';

export class BrightScriptCommands {

Expand All @@ -26,6 +28,8 @@ export class BrightScriptCommands {
public host: string;
public password: string;
public workspacePath: string;
private signingPassword: string;
private signedPackagePath: string;
private keypressNotifiers = [] as ((key: string, literalCharacter: boolean) => void)[];

public registerCommands() {
Expand Down Expand Up @@ -201,9 +205,78 @@ export class BrightScriptCommands {
}
});

this.registerCommand('rekeyDevice', async () => {
await this.rekeyDevice();
});

this.registerCommand('createPackage', async () => {
await this.createPackage();
});

this.registerCommand('rekeyAndPackage', async () => {
await this.rekeyDevice().then(async () => {
await this.createPackage();
});
});

this.registerKeyboardInputs();
}

private async rekeyDevice() {
await this.getRemoteHost();
await this.getRemotePassword();
await this.getSigningPassword();
await this.getSignedPackagePath();

await rokuDeploy.rekeyDevice({ host: this.host, password: this.password, signingPassword: this.signingPassword, rekeySignedPackage: this.signedPackagePath }
).then(() => void vscode.window.showInformationMessage(`Device successfully rekeyed!`));
}

private async createPackage() {
await this.getWorkspacePath();
let config = vscode.workspace.getConfiguration('launch', null);
const configurations = config.get<any[]>('configurations');
let configNames = [];
for (let config of configurations) {
configNames.push(config.name);
}

//show user a list of available launch configs to choose from
let selectedConfig = configurations[0];
let selectedConfigName = await vscode.window.showQuickPick(configNames, { placeHolder: 'Please select a config', canPickMany: false });
if (selectedConfigName) {
let selectedIndex = configNames.indexOf(selectedConfigName);
selectedConfig = configurations[selectedIndex];
}

if (selectedConfig.rootDir?.includes('${workspaceFolder}')) {
selectedConfig.rootDir = path.normalize(selectedConfig.rootDir.replace('${workspaceFolder}', this.workspacePath));
}

await this.getSigningPassword();
await this.getRemoteHost();
await this.getRemotePassword();

let rokuDeployOptions = {
rootDir: selectedConfig.rootDir,
files: selectedConfig.files,
outDir: this.workspacePath + '/out',
outFile: 'roku-' + selectedConfig.name.replace(/ /g, '-'),
retainStagingDir: true,
host: this.host,
password: this.password,
signingPassword: this.signingPassword
};

//create a zip and pkg file of the app based on the selected launch config
await rokuDeploy.createPackage(rokuDeployOptions).then(async () => {
let remotePkgPath = await rokuDeploy.signExistingPackage(rokuDeployOptions);
let localPkgFilePath = await rokuDeploy.retrieveSignedPackage(remotePkgPath, rokuDeployOptions).then(() => {
void vscode.window.showInformationMessage(`Package successfully created!`);
});
});
}

/**
* Registers all the commands for a-z, A-Z, 0-9, and all the primary character such as !, @, #, ', ", etc...
*/
Expand Down Expand Up @@ -405,6 +478,46 @@ export class BrightScriptCommands {
}
}

public async getSigningPassword() {
this.signingPassword = await this.context.workspaceState.get('signingPassword');
if (!this.signingPassword) {
let config = vscode.workspace.getConfiguration('brightscript.remoteControl', null);
this.signingPassword = config.get('signingPassword');
// eslint-disable-next-line no-template-curly-in-string
if (!this.signingPassword) {
this.signingPassword = await vscode.window.showInputBox({
placeHolder: 'Enter the signing password used for creating signed packages',
value: ''
});
}
}
if (!this.signingPassword) {
throw new Error('Can\'t send command: signingPassword is required.');
} else {
await this.context.workspaceState.update('signingPassword', this.signingPassword);
}
}

public async getSignedPackagePath() {
this.signedPackagePath = await this.context.workspaceState.get('signedPackagePath');
if (!this.signedPackagePath) {
let config = vscode.workspace.getConfiguration('brightscript.remoteControl', null);
this.signedPackagePath = config.get('signedPackagePath');
// eslint-disable-next-line no-template-curly-in-string
if (!this.signedPackagePath) {
this.signedPackagePath = await vscode.window.showInputBox({
placeHolder: 'Enter the path for the signed package',
value: ''
});
}
}
if (!this.signedPackagePath) {
throw new Error('Can\'t send command: Signed Package Path is required.');
} else {
await this.context.workspaceState.update('signedPackagePath', this.signedPackagePath);
}
}

public registerKeypressNotifier(notifier: (key: string, literalCharacter: boolean) => void) {
this.keypressNotifiers.push(notifier);
}
Expand Down

0 comments on commit ab5629e

Please sign in to comment.