Skip to content

Commit

Permalink
Merge pull request #56 from cazacutudor/device-rekey
Browse files Browse the repository at this point in the history
Implement rekey functionality
  • Loading branch information
nishtahir authored Oct 22, 2018
2 parents 587e70c + 8f43f95 commit 89054c5
Show file tree
Hide file tree
Showing 8 changed files with 149 additions and 21 deletions.
34 changes: 24 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ Join us in the #tooling channel on the [Roku Developers Slack](https://join.slac

## Project setup

You can install Ukor via NPM.
You can install Ukor via NPM.

```sh
npm install -g @willowtreeapps/ukor
Expand All @@ -50,7 +50,7 @@ A Ukor project is organized in a single `src` folder with properties files in or
- ukor.local
```

The `ukor.properties` file is the main ukor configuration file for the project and should be version controlled. The `ukor.local` file is a local properties file that contains local customizations for ukor overriding the `ukor.properties` file. This file is not expected to be version controlled.
The `ukor.properties` file is the main ukor configuration file for the project and should be version controlled. The `ukor.local` file is a local properties file that contains local customizations for ukor overriding the `ukor.properties` file. This file is not expected to be version controlled.

The `constants.yaml` file is *per-flavor*. In the file, you can define strings (or even any text to insert into a file), and can be identified with `@{some.category.id}` in brightscript OR xml source files.

Expand Down Expand Up @@ -83,7 +83,7 @@ rokus: {
## Constants
Each flavor can contain string resources specified in the `YAML` format by providing `constants.yaml` file. Strings can be referenced by their path specified in any `.xml` or `.brs` source files. For example,

Given a `constants.yaml` file:
Given a `constants.yaml` file:

```yml
strings:
Expand Down Expand Up @@ -117,6 +117,7 @@ Usage: ukor [options] [command]
make [flavors...] Bundle your channel into a zip to the build directory
install [flavor] [roku] [-c] Bundle then deploy your channel to a named roku
package <flavor> <roku> Package a channel flavor with a roku device
rekey <roku> Rekey your device (an packageReference is required)
lint <flavor> Lint a channel flavor
console [roku] Launch the Telnet console for the named roku
debugger [roku] Launch the Telnet debugger for the named roku
Expand All @@ -133,7 +134,7 @@ Usage: ukor [options] [command]
-v, --verbose Turn on verbose logging
```
## Quick reference
## Quick reference
* I want to make a new project
```
Expand All @@ -153,7 +154,7 @@ or
```
ukor install [flavor] [ip address] --auth=[username]:[password]
```
```
* I want to package my project using a device
```
Expand All @@ -165,6 +166,19 @@ or
ukor package [flavor] [ip address] --auth=[username]:[password]
```
* I want to rekey my device
```
ukor rekey [device]
```
or
```
ukor package [ip address] --auth=[username]:[password]
```
NOTE: you will need to define a `packageReference` in `ukor.properties.yaml`.
`packageReference` represent an signed release package.
## Testing
Ukor uses `UnitTestFramework.brs` as part of its unit test runner and test reporting feature. This is especially useful if you plan on having Continuous Integration as part of your workflow.
Expand All @@ -173,7 +187,7 @@ Ukor uses `UnitTestFramework.brs` as part of its unit test runner and test repor
First, copy the modified `UnitTestFramework.brs` in [lib/brs/](../master/lib/brs/UnitTestFramework.brs) to your `src/test/source/` folder, so it loads at startup for when testing.
> Note that the original `UnitTestFramework.brs` can be found [here](https://github.com/rokudev/unit-testing-framework)
> Note that the original `UnitTestFramework.brs` can be found [here](https://github.com/rokudev/unit-testing-framework)
Next, dd the following snippet in your startup function, after `screen.show()` but before the event loop
Expand All @@ -194,17 +208,17 @@ You should now be able to execute your test suite using the `test` command.

```
ukor test [flavor] [roku]
```
```

### What's happening?

Basically, we modified the rokudev `UnitTestFramework.brs` file to make a `JSON` of test results, and then `POST` that to the specified server. `ukor test [flavor]` builds and deploys the specified flavor with the `test` src folder, and then restarts the channel with parameters to run tests and point the results to the client machine. `ukor` will log the results, and also output results in `xml` and `junit` format to `.out/tests/ukorTests.[xml|junit]`.
Basically, we modified the rokudev `UnitTestFramework.brs` file to make a `JSON` of test results, and then `POST` that to the specified server. `ukor test [flavor]` builds and deploys the specified flavor with the `test` src folder, and then restarts the channel with parameters to run tests and point the results to the client machine. `ukor` will log the results, and also output results in `xml` and `junit` format to `.out/tests/ukorTests.[xml|junit]`.

notes:
notes:
- Ukor now copies `UnitTestFramework.brs` with `ukor init`!
- `UnitTestFramework.brs` is now up to date with the rokudev repo!

# Contributing to Ukor

Contributions and suggestions are more than welcome. Please see our [Code of Conduct](/CODE_OF_CONDUCT.md)
Contributions and suggestions are more than welcome. Please see our [Code of Conduct](/CODE_OF_CONDUCT.md)
as well as our [Contributing Guidelines ](/CONTRIBUTING.md) for more information.
59 changes: 59 additions & 0 deletions bin/ukor-rekey.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
const log = require('../lib/utils/log')
const utils = require('../lib/utils/utils')
const find = require('../lib/commands/find')
const rekey = require('../lib/commands/rekey')
const install = require('../lib/commands/install')
const package = require('../lib/commands/package')
const properties = require('../lib/utils/properties')
const program = require('../lib/utils/log-commander')

program
.arguments('[roku]')
.option(
'-r, --roku <name|id|ip>',
'Specify a roku. Ignored if passed as argument.'
)
.option('-a, --auth <user:pass>', 'Set username and password for roku.')
.parse(process.argv)

let args = program.args
let roku = args[0] || program.roku || properties.defaults.roku

try {
var auth = program.auth || properties.rokus[roku]['auth']
if (typeof(auth) === 'string') {
auth = {
user: auth.split(':')[0],
pass: auth.split(':')[1]
}
}
} catch (e) {
log.error('no auth defined for roku: ' + roku)
process.exit(-1)
}

let options = {
flavor: 'main',
roku,
auth,
name: ''
}
for (let key in options) {
if (!options[key] && key != 'name') {
log.error('%s options is undefined')
log.pretty('error', 'options:', options)
process.exit(-1)
}
}

if (program['verbose']) {
log.level = 'verbose'
}

if (program['debug']) {
log.level = 'debug'
}

find.findDeviceBySerialNo(utils.getUsn(options), 5, ip => {
ip ? rekey.rekey(options, ip) : null
})
4 changes: 4 additions & 0 deletions bin/ukor.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ program
'package <flavor> <roku>',
'Package a channel flavor with a roku device'
)
.command(
'rekey <roku>',
'Rekey your device (an packageReference is required)'
)
.command(
'lint <flavor>',
'Lint a channel flavor'
Expand Down
8 changes: 1 addition & 7 deletions lib/commands/install.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,7 @@ function doInstall(test, options, callback) {
if (utils.parseRoku(options.roku) == 'ip') {
upload(options, options.roku, callback)
} else {
let usn = ''
if (utils.parseRoku(options.roku) == 'name') {
usn = properties.rokus[options.roku].serial
} else {
usn = options.roku
}
find.findDeviceBySerialNo(usn, 5, ip => {
find.findDeviceBySerialNo(utils.getUsn(options), 5, ip => {
ip ? upload(options, ip, callback) : null
})
}
Expand Down
4 changes: 2 additions & 2 deletions lib/commands/package.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ function create(options, ip) {
if (error || !body) {
log.error('Generate package failed:')
log.error(error)
log.error('Failture http code:' + response.statusCode)
} else {
urls = parseBody(body)

Expand All @@ -38,7 +37,8 @@ function create(options, ip) {
download(options, ip, packageName)
}
} else {
log.error('Falied to find the package in body response');
log.error('Falied to find the package in body response')
log.info('TIP: Try to rekey your device')
}
}
}
Expand Down
48 changes: 48 additions & 0 deletions lib/commands/rekey.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
const fs = require('fs')
const request = require('request')
const log = require('../utils/log')
const properties = require('../utils/properties')

function rekey(options, ip) {
if (properties.packageReference == null) {
log.error("packageReference field is missing (ukor.properties)")
return
}

const form = {
mysubmit: 'Rekey',
passwd: properties.packageKey,
archive: fs.createReadStream(properties.packageReference)
}

options.auth.sendImmediately = false
request.post(
{
url: 'http://' + ip + '/plugin_inspect',
formData: form,
auth: options.auth
},
(error, response, body) => {
if (error || !body) {
log.error('Rekey device falied:')
log.error(error)
} else {
result = parseBody(body)

if (result[0].indexOf('Success') !== -1) {
log.info(`The device was rekeyed with: ${properties.packageKey}`)
} else {
log.error('Falied to rekey');
}
}
}
)
}

function parseBody(body) {
return body.match(/<font color=\"red\">(.*?)<\/font>/g)
}

module.exports = {
rekey
}
6 changes: 5 additions & 1 deletion lib/utils/schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,10 @@ module.exports = {
packageKey: {
type: 'string',
pattern: '\S*',
},
packageReference: {
type: 'string',
pattern: '\S*',
}
}
}
}
7 changes: 6 additions & 1 deletion lib/utils/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,15 @@ function getDeviceInfo(ip, callback) {
})
}

function getUsn(options) {
return (parseRoku(options.roku) == 'name') ? properties.rokus[options.roku].serial : options.roku
}

module.exports = {
parseRoku,
parseAuth,
continueIfExists,
getAllSourceFiles,
getDeviceInfo
getDeviceInfo,
getUsn
}

0 comments on commit 89054c5

Please sign in to comment.