Skip to content

Commit

Permalink
feat(fal): CORE-8718 - Add support for downloading firmware assets au…
Browse files Browse the repository at this point in the history
…tomatically
  • Loading branch information
matthewh committed Aug 19, 2024
1 parent a117fcc commit 01605fc
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 12 deletions.
20 changes: 19 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ Creates a new instance with the given options. The following options are support
- `irq`: system IRQs, 1-16 ranges must be specified
- `port`: tcp port for vMMIO usage

Example:
#### Example:

```javascript=
// create instance
Expand All @@ -282,6 +282,24 @@ let instance = await project.createInstance({
await instance.finishRestore();
```

#### Example: Handling Firmware Assets

```
❯ node myscript.js
Error: This instance requires additional firmware assets. To automatically download firmware assets and associate them
with your domain, set the environment variable FETCH_FIRMWARE_ASSETS=1
```

Some recent firmwares require additional files that must be downloaded by the api client and associated with your domain.
The Corellium API can download these resources and associated them with your domain. To enable automatic download, set
the environment variable `FETCH_FIRMWARE_ASSETS=1`.

```
❯ env FETCH_FIRMWARE_ASSETS=1 node myscript.js
Creating ios device...
Created 741d5b9c-01dd-4878-b16f-8d6aa513c9c4
```

## class Instance

**Note:** instances of class `Instance` are only supposed to be retrieved by `Project#instances()`, `Project#getInstance()`, or `Project#createInstance`.
Expand Down
Empty file.
2 changes: 1 addition & 1 deletion package-lock.json

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

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@corellium/corellium-api",
"version": "1.7.6",
"version": "1.8.0",
"description": "Supported nodejs library for interacting with the Corellium service and VMs",
"main": "src/corellium.js",
"husky": {
Expand Down
69 changes: 64 additions & 5 deletions src/project.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ const { v4: uuidv4 } = require('uuid')
const util = require('util')
const fs = require('fs')
const { compress, uploadFile } = require('./images')
const path = require('path')
const os = require('os')
const { fetch } = require('./util/fetch')

/**
* @typedef {object} ProjectKey
Expand Down Expand Up @@ -138,11 +141,42 @@ class Project {
* await instance.finishRestore();
*/
async createInstance (options) {
const { id } = await fetchApi(this, '/instances', {
method: 'POST',
json: Object.assign({}, options, { project: this.id })
})
return await this.getInstance(id)
try {
const { id } = await fetchApi(this, '/instances', {
method: 'POST',
json: Object.assign({}, options, { project: this.id })
})
return await this.getInstance(id)
} catch (err) {
if (err.field === 'firmware_asset') {
if (process.env.FETCH_FIRMWARE_ASSETS !== '1') {
throw new Error('This instance requires additional firmware assets. To automatically download firmware assets and associate them with your domain, set the environment variable FETCH_FIRMWARE_ASSETS=1')
}
if (err.originalError.missingFwAssets && err.originalError.missingFwAssets.length > 0) {
for (const firmwareAssetUrl of err.originalError.missingFwAssets) {
const response = await fetch(firmwareAssetUrl, { response: 'raw' })
const fwAssetPath = path.join(os.tmpdir(), `${uuidv4()}.fwasset`)
if (response.ok) {
const stream = fs.createWriteStream(fwAssetPath)
response.body.pipe(stream)

await new Promise(resolve => response.body.on('finish', () => {
stream.end()
resolve()
}))

await new Promise(resolve => stream.on('finish', () => { resolve() }))

await this.uploadFirmwareAsset(fwAssetPath, encodeURIComponent(firmwareAssetUrl), () => {})
}
}
}

return this.createInstance(options)
} else {
throw err
}
}
}

/**
Expand Down Expand Up @@ -395,6 +429,31 @@ class Project {
return { id: imageId, name }
}

/**
* Add a firmware asset image to a proejct for use in creating new instances.
* @param filePath - The path on the local file system to get the firmware asset file
* @param name - The name of the file to identify the file on the server, usually the full url
* @param progress
* @returns {Promise<{name, id: *}>}
*/
async uploadFirmwareAsset (filePath, name, progress) {
const imageId = uuidv4()
const token = await this.getToken()
const url =
this.api +
'/projects/' +
encodeURIComponent(this.id) +
'/image-upload/' +
encodeURIComponent('fwasset') +
'/' +
encodeURIComponent(imageId) +
'/' +
encodeURIComponent(name)

await uploadFile(token, url, filePath, progress)
return { id: imageId, name }
}

/**
* Add an image to the project. These images may be removed at any time and are meant to facilitate creating a new Instance with images.
*
Expand Down
9 changes: 5 additions & 4 deletions src/util/fetch.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,19 @@ class CorelliumError extends Error {
this.name = this.constructor.name
this.field = error.field
this.code = code
this.originalError = error
}
}

async function fetch (url, options) {
if (options.headers === undefined) options.headers = {}
if (options && options.headers === undefined) options.headers = {}

if (options.json !== undefined) {
if (options && options.json !== undefined) {
options.body = JSON.stringify(options.json)
options.headers['Content-Type'] = 'application/json'
delete options.json
}
if (options.token !== undefined) {
if (options && options.token !== undefined) {
options.headers.Authorization = options.token
}

Expand All @@ -46,7 +47,7 @@ async function fetch (url, options) {

throw new Error(`${options.method || 'GET'} ${url} -- ${res.status} ${res.statusText}`)
}
if (options.response === 'raw') return res
if (options && options.response === 'raw') return res
return await res.json()
}

Expand Down

0 comments on commit 01605fc

Please sign in to comment.