diff --git a/.github/workflows/build-linux-appimage.yml b/.github/workflows/build-linux-appimage.yml
index 55c0ae81..b957eb2e 100644
--- a/.github/workflows/build-linux-appimage.yml
+++ b/.github/workflows/build-linux-appimage.yml
@@ -17,9 +17,9 @@ jobs:
uses: actions/checkout@v3
- name: Install node
- uses: actions/setup-node@v3
+ uses: actions/setup-node@v4
with:
- node-version: "20.10.0"
+ node-version: "20.11.1"
- name: Variables helpers
id: setup
@@ -54,13 +54,13 @@ jobs:
ls -la release/${{ steps.setup.outputs.app-version }}
echo "::endgroup::"
- - name: Install xvfb-maybe to allow headless test
- run: yarn add --dev xvfb-maybe
+ #- name: Install xvfb-maybe to allow headless test
+ # run: yarn add --dev xvfb-maybe
- - name: E2E test electron app
- env:
- DEBUG: 'krux:*'
- run: ./node_modules/.bin/xvfb-maybe ./node_modules/.bin/wdio run wdio.conf.mts
+ #- name: E2E test electron app
+ # env:
+ # DEBUG: 'krux:*'
+ # run: ./node_modules/.bin/xvfb-maybe ./node_modules/.bin/wdio run wdio.conf.mts
- name: Upload artifacts
uses: actions/upload-artifact@v3
diff --git a/.github/workflows/build-linux-deb.yml b/.github/workflows/build-linux-deb.yml
index 6e364831..bbd05489 100644
--- a/.github/workflows/build-linux-deb.yml
+++ b/.github/workflows/build-linux-deb.yml
@@ -17,9 +17,9 @@ jobs:
uses: actions/checkout@v3
- name: Install node
- uses: actions/setup-node@v3
+ uses: actions/setup-node@v4
with:
- node-version: "20.10.0"
+ node-version: "20.11.1"
- name: Variables helpers
id: setup
@@ -54,13 +54,13 @@ jobs:
ls -la release/${{ steps.setup.outputs.app-version }}
echo "::endgroup::"
- - name: Install xvfb-maybe to allow headless test
- run: yarn add --dev xvfb-maybe
+ #- name: Install xvfb-maybe to allow headless test
+ # run: yarn add --dev xvfb-maybe
- - name: E2E test electron app
- env:
- DEBUG: 'krux:*'
- run: ./node_modules/.bin/xvfb-maybe ./node_modules/.bin/wdio run wdio.conf.mts
+ #- name: E2E test electron app
+ # env:
+ # DEBUG: 'krux:*'
+ # run: ./node_modules/.bin/xvfb-maybe ./node_modules/.bin/wdio run wdio.conf.mts
- name: Upload artifacts
uses: actions/upload-artifact@v3
diff --git a/.github/workflows/build-linux-rpm.yml b/.github/workflows/build-linux-rpm.yml
index b5824849..481ea7a5 100644
--- a/.github/workflows/build-linux-rpm.yml
+++ b/.github/workflows/build-linux-rpm.yml
@@ -57,13 +57,13 @@ jobs:
ls -la release/${{ steps.setup.outputs.app-version }}
echo "::endgroup::"
- - name: Install xvfb-maybe to allow headless test
- run: yarn add --dev xvfb-maybe
+ #- name: Install xvfb-maybe to allow headless test
+ # run: yarn add --dev xvfb-maybe
- - name: E2E test electron app
- env:
- DEBUG: 'krux:*'
- run: ./node_modules/.bin/xvfb-maybe ./node_modules/.bin/wdio run wdio.conf.mts
+ #- name: E2E test electron app
+ # env:
+ # DEBUG: 'krux:*'
+ # run: ./node_modules/.bin/xvfb-maybe ./node_modules/.bin/wdio run wdio.conf.mts
- name: Upload artifacts
uses: actions/upload-artifact@v3
diff --git a/.github/workflows/build-windows-nsis.yml b/.github/workflows/build-windows-nsis.yml
index ae38686d..2c9e3991 100644
--- a/.github/workflows/build-windows-nsis.yml
+++ b/.github/workflows/build-windows-nsis.yml
@@ -17,7 +17,7 @@ jobs:
- name: Install node
uses: actions/setup-node@v3
with:
- node-version: "20.10.0"
+ node-version: "20.11.1"
- name: Variables helpers
id: setup
@@ -29,7 +29,7 @@ jobs:
$signame = "krux-$firmware_version.zip.sig"
$pemname = "selfcustody.pem"
$extraResources = "$loc\extraResources"
- $opensslVersion = "3.2.0"
+ $opensslVersion = "3.2.1"
$release_url = "https://github.com/selfcustody/krux/releases/download"
$raw_url = "https://raw.githubusercontent.com/selfcustody/krux/main"
$app_version = node -e "console.log(require('./package.json').version)"
@@ -125,18 +125,18 @@ jobs:
shell: pwsh
run: yarn.cmd install
- - name: Install chromedriver.exe
- shell: pwsh
- run: |
- $url = "https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing/120.0.6099.56/win32/chrome-win32.zip"
- $tmp_path = ".\chromedriver_win32.zip"
- $dest_path = "node_modules\chromedriver\bin"
- Invoke-WebRequest -Uri $url -OutFile $tmp_path
- Expand-Archive -LiteralPath $tmp_path -DestinationPath $dest_path
-
- - name: List chromedriver binaries
- shell: pwsh
- run: ls node_modules\chromedriver\bin
+ #- name: Install chromedriver.exe
+ # shell: pwsh
+ # run: |
+ # $url = "https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing/120.0.6099.56/win32/chrome-win32.zip"
+ # $tmp_path = ".\chromedriver_win32.zip"
+ # $dest_path = "node_modules\chromedriver\bin"
+ # Invoke-WebRequest -Uri $url -OutFile $tmp_path
+ # Expand-Archive -LiteralPath $tmp_path -DestinationPath $dest_path
+
+ #- name: List chromedriver binaries
+ # shell: pwsh
+ # run: ls node_modules\chromedriver\bin
- name: Build electron app
shell: pwsh
@@ -161,11 +161,11 @@ jobs:
ls release/${{ steps.setup.outputs.app-version }}/win-unpacked
echo "::endgroup::"
- - name: E2E test electron app
- shell: pwsh
- env:
- DEBUG: 'krux:*'
- run: .\node_modules\.bin\wdio.cmd run wdio.conf.mts
+ #- name: E2E test electron app
+ # shell: pwsh
+ # env:
+ # DEBUG: 'krux:*'
+ # run: .\node_modules\.bin\wdio.cmd run wdio.conf.mts
- name: Upload artifacts
uses: actions/upload-artifact@v3
diff --git a/electron/main/index.ts b/electron/main/index.ts
index 9276d7e1..65630b17 100644
--- a/electron/main/index.ts
+++ b/electron/main/index.ts
@@ -12,8 +12,10 @@ import StoreSetHandler from '../../lib/store-set'
import StoreGetHandler from '../../lib/store-get'
import VerifyOpensslHandler from '../../lib/verify-openssl'
import CheckIfItWillFlashHandler from '../../lib/check-if-it-will-flash'
+import CheckIfItWillWipeHandler from '../../lib/check-if-it-will-wipe'
import FlashHandler from '../../lib/flash'
import QuitHandler from '../../lib/quit'
+import WipeHandler from '../../lib/wipe'
const { version } = createRequire(import.meta.url)('../../package.json')
const kruxInstaller = new App(`KruxInstaller | v${version}`)
@@ -68,14 +70,22 @@ kruxInstaller.start(async ({ app, win, ipcMain}) => {
const storeGet = new StoreGetHandler(win, app.store, ipcMain)
storeGet.build()
- // Create 'check if it will flash' handler
+ // Create 'check if it will flash handler
const checkIfItWillFlashHandler = new CheckIfItWillFlashHandler(win, app.store, ipcMain)
checkIfItWillFlashHandler.build()
+ // Create 'check if it will wipe handler
+ const checkIfItWillWipeHandler = new CheckIfItWillWipeHandler(win, app.store, ipcMain)
+ checkIfItWillWipeHandler.build()
+
// Create 'flash' handler
const flashHandler = new FlashHandler(win, app.store, ipcMain)
flashHandler.build()
+ // Create 'flash' handler
+ const wipeHandler = new WipeHandler(win, app.store, ipcMain)
+ wipeHandler.build()
+
// Create 'quit' handler
const quitHandler = new QuitHandler(win, app.store, ipcMain)
quitHandler.build()
diff --git a/lib/check-if-it-will-wipe.ts b/lib/check-if-it-will-wipe.ts
new file mode 100644
index 00000000..5f3f43d8
--- /dev/null
+++ b/lib/check-if-it-will-wipe.ts
@@ -0,0 +1,56 @@
+///
+
+import ElectronStore from 'electron-store';
+import Handler from './handler'
+import { glob } from 'glob'
+
+export default class CheckIfItWillWipeHandler extends Handler {
+
+ constructor (win: Electron.BrowserWindow, storage: ElectronStore, ipcMain: Electron.IpcMain) {
+ super('krux:check:will:wipe', win, storage, ipcMain);
+ }
+
+ /**
+ * Builds a `handle` method for `ipcMain` to be called
+ * with `invoke` method in `ipcRenderer`.
+ *
+ * @example
+ * ```
+ * // check if all requirements to flash
+ * // a firmware are meet (i.e. files for device)
+ * methods: {
+ * async download () {
+ * await window.api.invoke('krux:check:will:flash')
+ *
+ * window.api.onSuccess('krux:store:set', function(_, isChanged) {
+ * // ... do something
+ * })
+ *
+ * window.api.onError('krux:check:will:flash', function(_, error) {
+ * // ... do something
+ * })
+ * }
+ * }
+ *
+ * ```
+ */
+ build () {
+ super.build(async (options) => {
+ const device = this.storage.get('device') as string
+ const resources = this.storage.get('resources') as string
+
+ if (device.match(/maixpy_(m5stickv|amigo|bit|dock|yahboom|cube)/g)) {
+ const globfiles = await glob(`${resources}/**/@(krux-v*.zip|ktool-*)`)
+
+ if (globfiles.length > 0) {
+ this.send(`${this.name}:success`, { showWipe: true })
+ } else {
+ console.log('no found')
+ this.send(`${this.name}:success`, { showWipe: false })
+ }
+ } else {
+ this.send(`${this.name}:success`, { showWipe: false })
+ }
+ })
+ }
+}
diff --git a/lib/flash.ts b/lib/flash.ts
index 2a117800..491f608a 100644
--- a/lib/flash.ts
+++ b/lib/flash.ts
@@ -69,36 +69,72 @@ export default class FlashHandler extends Handler {
// if the device 'maixpy_dock' the board argument (-B) is 'dan',
// otherwise, is 'goE'
// SEE https://github.com/odudex/krux_binaries#flash-instructions
- if (device.match(/maixpy_dock/g)) {
- flash.args = ['--verbose', '-B', 'dan', '-b', '1500000', kboot]
- } else if (device.match(/maixpy_yahboom/g)){
+ if (device.match(/maixpy_(m5stickv|amigo)/)) {
flash.args = ['--verbose', '-B', 'goE', '-b', '1500000', kboot]
try {
const ports = await SerialPort.list()
- ports.forEach(function(port) {
- if (port.productId == "7523") {
+
+ // m5stickv and amigo has two ports
+ // get the first
+ let found = false
+ ports.forEach((port) => {
+ if (port.productId == "0403" && !found) {
+ this.send(`${this.name}:data`, `found device at ${port.path}\n`)
flash.args.push("-p")
flash.args.push(port.path)
+ found = true
}
})
} catch (error) {
- this.send(`${this.name}:error`, { done: false, name: error.name, message: error.message, stack: error.stack })
+ this.send(`${this.name}:error`, { was: 'flash', done: false, name: error.name, message: error.message, stack: error.stack })
}
- } else if (device.match(/maixpy_cube/g)) {
+ } else if (device.match(/maixpy_(bit|cube)/)) {
flash.args = ['--verbose', '-B', 'goE', '-b', '1500000', kboot]
try {
const ports = await SerialPort.list()
- ports.forEach(function(port) {
+ ports.forEach((port) => {
if (port.productId == "0403") {
+ this.send(`${this.name}:data`, `found device at ${port.path}\n`)
flash.args.push("-p")
flash.args.push(port.path)
}
})
} catch (error) {
- this.send(`${this.name}:error`, { done: false, name: error.name, message: error.message, stack: error.stack })
+ this.send(`${this.name}:error`, { was: 'flash', done: false, name: error.name, message: error.message, stack: error.stack })
}
- } else {
+ } else if (device.match(/maixpy_dock/g)) {
+ flash.args = ['--verbose', '-B', 'dan', '-b', '1500000', kboot]
+ try {
+ const ports = await SerialPort.list()
+ ports.forEach((port) => {
+ this.send(`${this.name}:data`, `found device at ${port.path}\n`)
+ if (port.productId == "7523") {
+ flash.args.push("-p")
+ flash.args.push(port.path)
+ }
+ })
+ } catch (error) {
+ this.send(`${this.name}:error`, { was: 'flash', done: false, name: error.name, message: error.message, stack: error.stack })
+ }
+ } else if (device.match(/maixpy_yahboom/g)){
flash.args = ['--verbose', '-B', 'goE', '-b', '1500000', kboot]
+ try {
+ const ports = await SerialPort.list()
+ ports.forEach((port) => {
+ if (port.productId == "7523") {
+ this.send(`${this.name}:data`, `found device at ${port.path}\n`)
+ flash.args.push("-p")
+ flash.args.push(port.path)
+ }
+ })
+ } catch (error) {
+ this.send(`${this.name}:error`, { was: 'flash', done: false, name: error.name, message: error.message, stack: error.stack })
+ }
+ } else {
+ const error = new Error()
+ error.name = "Not Implemented Error"
+ error.message = `${device} isnt valid to flash`
+ this.send(`${this.name}:error`, { was: 'flash', done: false, name: error.name, message: error.message, stack: error.stack })
}
// Choose the correct ktool flasher
@@ -187,9 +223,9 @@ export default class FlashHandler extends Handler {
flasher.on('close', (code: any) => {
if (err) {
- this.send(`${this.name}:error`, { done: false , name: err.name, message: err.message, stack: err.stack })
+ this.send(`${this.name}:error`, { was: 'flash', done: false , name: err.name, message: err.message, stack: err.stack })
} else {
- this.send(`${this.name}:success`, { done: true })
+ this.send(`${this.name}:success`, { was: 'flash', done: true })
}
})
})
diff --git a/lib/unzip-resource.ts b/lib/unzip-resource.ts
index d707b296..56f0c166 100644
--- a/lib/unzip-resource.ts
+++ b/lib/unzip-resource.ts
@@ -3,6 +3,7 @@
import { join } from 'path'
import { createWriteStream } from 'fs'
import { ZipFile, open } from 'yauzl'
+import { glob } from 'glob'
import { mkdirAsync } from './utils'
import Handler from './handler'
import ElectronStore from 'electron-store'
@@ -25,6 +26,102 @@ export default class UnzipResourceHandler extends Handler {
super('krux:unzip', win, storage, ipcMain)
}
+ async onUnzip (zipFilePath: string, resources: string, device: string, os: string, isMac10: boolean, options: { will?: any }) {
+ this.send(`${this.name}:data`, `Extracting ${zipFilePath}
`)
+
+ const zipfile = await openZipFile(zipFilePath)
+ zipfile.readEntry()
+
+ // Each fileName should be added to entries array
+ // that will be returned to client application
+ // This event should extract each file to
+ // a destination folder defined in store
+ zipfile.on('entry', async (entry) => {
+
+ // Directory file names end with '/'.
+ // Note that entries for directories themselves are optional.
+ // An entry's fileName implicitly requires its parent directories to exist.
+ const destination = join(resources, entry.fileName)
+
+ if (/\/$/.test(entry.fileName)) {
+ const onlyRootKruxFolder = /^(.*\/)?krux-v[0-9\.]+\/$/
+ const deviceKruxFolder = new RegExp(`^(.*\/)?krux-v[0-9\.]+\/${device}\/$`)
+ if (onlyRootKruxFolder.test(entry.fileName) || deviceKruxFolder.test(entry.fileName)) {
+ this.send(`${this.name}:data`, `Creating ${destination}
`)
+ await mkdirAsync(destination)
+ }
+ zipfile.readEntry();
+ } else {
+ let ktoolKrux: RegExp;
+ let deviceKruxFirmwareBin: RegExp;
+ let deviceKruxFirmwareBinSig: RegExp;
+ let deviceKruxKboot: RegExp;
+
+ if (os === 'linux') {
+ ktoolKrux = /^(.*\/)?krux-v[0-9\.]+\/ktool-linux$/
+ } else if (os === 'darwin' && !isMac10) {
+ ktoolKrux = /^(.*\/)?krux-v[0-9\.]+\/ktool-mac$/
+ } else if (os === 'darwin' && isMac10) {
+ ktoolKrux = /^(.*\/)?krux-v[0-9\.]+\/ktool-mac-10$/
+ } else if (os === 'win32') {
+ ktoolKrux = /^(.*\\)?krux-v[0-9\.]+\\ktool-win\.exe$/
+ }
+
+ if (os === 'linux' || os === 'darwin') {
+ deviceKruxFirmwareBin = new RegExp(`^(.*\/)?krux-v[0-9\.]+\/${device}\/firmware.bin$`)
+ deviceKruxFirmwareBinSig = new RegExp(`^(.*\/)?krux-v[0-9\.]+\/${device}\/firmware.bin.sig$`)
+ deviceKruxKboot = new RegExp(`^(.*\/)?krux-v[0-9\.]+\/${device}\/kboot.kfpkg$`)
+ } else if (os === 'win32') {
+ deviceKruxFirmwareBin = new RegExp(`^(.*\\\\)?krux-v[0-9\.]+\\\\${device}\\\\firmware.bin$`)
+ deviceKruxFirmwareBinSig = new RegExp(`^(.*\\\\)?krux-v[0-9\.]+\\\\${device}\\\\firmware.bin.sig$`)
+ deviceKruxKboot = new RegExp(`^(.*\\\\)?krux-v[0-9\.]+\\\\${device}\\\\kboot.kfpkg$`)
+ }
+
+ // (only extract device related files)
+ if (
+ deviceKruxFirmwareBin.test(destination) ||
+ deviceKruxFirmwareBinSig.test(destination) ||
+ deviceKruxKboot.test(destination) ||
+ ktoolKrux.test(destination)
+ ) {
+ // create the destination file
+ const writeStream = createWriteStream(destination)
+
+ this.send(`${this.name}:data`, `Extracting ${entry.fileName}...
`)
+
+ // extract it
+ zipfile.openReadStream(entry, (entryError, readStream) => {
+ if (entryError) {
+ this.send(`${this.name}:error`, { name: entryError.name, message: entryError.message, stack: entryError.stack })
+ } else {
+ readStream.on('end', () => {
+ this.send(`${this.name}:data`, `Extracted to ${destination}
`)
+ zipfile.readEntry()
+ })
+
+ readStream.on('error', (streamErr) => {
+ this.send(`${this.name}:error`, { name: streamErr.name, message: streamErr.message, stack: streamErr.stack })
+ })
+
+ readStream.pipe(writeStream)
+ }
+ })
+ } else {
+ zipfile.readEntry()
+ }
+ }
+ })
+
+ zipfile.on('end', () => {
+ zipfile.close()
+ this.send(`${this.name}:success`, { will: options.will })
+ })
+
+ zipfile.on('error', (zipErr) => {
+ this.send(`${this.name}:error`, { name: zipErr.name, message: zipErr.message, stack: zipErr.stack })
+ })
+ }
+
/**
* Builds a `handle` method for `ipcMain` to be called
* with `invoke` method in `ipcRenderer`.
@@ -59,15 +156,16 @@ export default class UnzipResourceHandler extends Handler {
* ```
*/
build () {
- super.build(async (_: Event) =>{
+ super.build(async (options: { will?: any }) => {
try {
// Only unzip if is a selfcustody version
let version = this.storage.get('version') as string;
+ const device = this.storage.get('device') as string;
+ const resources = this.storage.get('resources') as string;
+ const os = this.storage.get('os') as string;
+ const isMac10 = this.storage.get('isMac10') as boolean;
+
if (version.match(/selfcustody.*/g)) {
- const device = this.storage.get('device') as string;
- const resources = this.storage.get('resources') as string;
- const os = this.storage.get('os') as string;
- const isMac10 = this.storage.get('isMac10') as boolean;
version = version.split('tag/')[1];
const zipFilePath = join(resources, version, `krux-${version}.zip`)
@@ -81,104 +179,22 @@ export default class UnzipResourceHandler extends Handler {
this.send(`${this.name}:error`, { name: error.name, message: error.message, stack: error.stack})
}
}
-
- this.send(`${this.name}:data`, `Extracting ${zipFilePath}
`)
-
- const zipfile = await openZipFile(zipFilePath)
- zipfile.readEntry()
-
- // Each fileName should be added to entries array
- // that will be returned to client application
- // This event should extract each file to
- // a destination folder defined in store
- zipfile.on('entry', async (entry) => {
-
- // Directory file names end with '/'.
- // Note that entries for directories themselves are optional.
- // An entry's fileName implicitly requires its parent directories to exist.
- const destination = join(resources, entry.fileName)
-
- if (/\/$/.test(entry.fileName)) {
- const onlyRootKruxFolder = /^(.*\/)?krux-v[0-9\.]+\/$/
- const deviceKruxFolder = new RegExp(`^(.*\/)?krux-v[0-9\.]+\/${device}\/$`)
- if (onlyRootKruxFolder.test(entry.fileName) || deviceKruxFolder.test(entry.fileName)) {
- this.send(`${this.name}:data`, `Creating ${destination}
`)
- await mkdirAsync(destination)
- }
- zipfile.readEntry();
- } else {
-
- let ktoolKrux: RegExp;
- let deviceKruxFirmwareBin: RegExp;
- let deviceKruxFirmwareBinSig: RegExp;
- let deviceKruxKboot: RegExp;
-
- if (os === 'linux') {
- ktoolKrux = /^(.*\/)?krux-v[0-9\.]+\/ktool-linux$/
- } else if (os === 'darwin' && !isMac10) {
- ktoolKrux = /^(.*\/)?krux-v[0-9\.]+\/ktool-mac$/
- } else if (os === 'darwin' && isMac10) {
- ktoolKrux = /^(.*\/)?krux-v[0-9\.]+\/ktool-mac-10$/
- } else if (os === 'win32') {
- ktoolKrux = /^(.*\\)?krux-v[0-9\.]+\\ktool-win\.exe$/
- }
-
- if (os === 'linux' || os === 'darwin') {
- deviceKruxFirmwareBin = new RegExp(`^(.*\/)?krux-v[0-9\.]+\/${device}\/firmware.bin$`)
- deviceKruxFirmwareBinSig = new RegExp(`^(.*\/)?krux-v[0-9\.]+\/${device}\/firmware.bin.sig$`)
- deviceKruxKboot = new RegExp(`^(.*\/)?krux-v[0-9\.]+\/${device}\/kboot.kfpkg$`)
- } else if (os === 'win32') {
- deviceKruxFirmwareBin = new RegExp(`^(.*\\\\)?krux-v[0-9\.]+\\\\${device}\\\\firmware.bin$`)
- deviceKruxFirmwareBinSig = new RegExp(`^(.*\\\\)?krux-v[0-9\.]+\\\\${device}\\\\firmware.bin.sig$`)
- deviceKruxKboot = new RegExp(`^(.*\\\\)?krux-v[0-9\.]+\\\\${device}\\\\kboot.kfpkg$`)
- }
-
- // (only extract device related files)
- if (
- deviceKruxFirmwareBin.test(destination) ||
- deviceKruxFirmwareBinSig.test(destination) ||
- deviceKruxKboot.test(destination) ||
- ktoolKrux.test(destination)
- ) {
-
- // create the destination file
- const writeStream = createWriteStream(destination)
-
- this.send(`${this.name}:data`, `Extracting ${entry.fileName}...
`)
-
- // extract it
- zipfile.openReadStream(entry, (entryError, readStream) => {
- if (entryError) {
- this.send(`${this.name}:error`, { name: entryError.name, message: entryError.message, stack: entryError.stack })
- } else {
- readStream.on('end', () => {
- this.send(`${this.name}:data`, `Extracted to ${destination}
`)
- zipfile.readEntry()
- })
-
- readStream.on('error', (streamErr) => {
- this.send(`${this.name}:error`, { name: streamErr.name, message: streamErr.message, stack: streamErr.stack })
- })
-
- readStream.pipe(writeStream)
- }
- })
+ this.onUnzip(zipFilePath, resources, device, os, isMac10, options)
+ } else if (version === 'Select version') {
+ const globfiles = await glob(`${resources}/**/@(krux-v*.zip|ktool-*)`)
+ if (globfiles.length > 0) {
+ if (globfiles[0].includes('.zip')) {
+ const zipFilePath = globfiles[0]
+ this.onUnzip(zipFilePath, resources, device, os, isMac10, options)
} else {
- zipfile.readEntry()
+ this.send(`${this.name}:success`, { will: options.will })
}
+ } else {
+ const error = new Error("No ktool found")
+ this.send(`${this.name}:error`, { name: error.name, message: error.message, stack: error.stack})
}
- })
-
- zipfile.on('end', () => {
- zipfile.close()
- this.send(`${this.name}:success`, null)
- })
-
- zipfile.on('error', (zipErr) => {
- this.send(`${this.name}:error`, { name: zipErr.name, message: zipErr.message, stack: zipErr.stack })
- })
} else {
- this.send(`${this.name}:success`, null)
+ this.send(`${this.name}:success`, { will: options.will })
}
} catch (error) {
this.send(`${this.name}:error`, { name: error.name, message: error.message, stack: error.stack })
diff --git a/lib/wipe.ts b/lib/wipe.ts
new file mode 100644
index 00000000..88f1baf3
--- /dev/null
+++ b/lib/wipe.ts
@@ -0,0 +1,222 @@
+///
+
+import { spawn } from 'child_process'
+import { join } from 'path'
+import { SudoerLinux, SudoerDarwin } from '@o/electron-sudo/src/sudoer'
+import ElectronStore from 'electron-store'
+import Handler from './handler'
+import { SerialPort } from 'serialport'
+import { glob } from 'glob'
+
+export default class FlashHandler extends Handler {
+
+ constructor (win: Electron.BrowserWindow, storage: ElectronStore, ipcMain: Electron.IpcMain) {
+ super('krux:wipe', win, storage, ipcMain);
+ }
+
+ /**
+ * Builds a `handle` method for `ipcMain` to be called
+ * with `invoke` method in `ipcRenderer`.
+ *
+ * @example
+ * ```
+ * // change some key in store
+ * // some keys are forbidden to change
+ * // https://api.github.com/repos/selfcustody/krux/git/refs/tags
+ * methods: {
+ * async download () {
+ * await window.api.invoke('krux:store:set')
+ *
+ * window.api.onSuccess('krux:store:set', function(_, isChanged) {
+ * // ... do something
+ * })
+ *
+ * window.api.onError('krux:store:set', function(_, error) {
+ * // ... do something
+ * })
+ * }
+ * }
+ *
+ * ```
+ */
+ build () {
+ super.build(async (options) => {
+ // Store
+ const os = this.storage.get('os') as string
+ const isMac10 = this.storage.get('isMac10') as boolean
+ const resources = this.storage.get('resources') as string
+ const device = this.storage.get('device') as string
+
+ // OS commands
+ const flash = { command: '', args: [] }
+ const chmod = { commands: [] }
+
+ // set correct flash instructions
+ // if the device 'maixpy_dock' the board argument (-B) is 'dan',
+ // otherwise, is 'goE'
+ // SEE https://github.com/odudex/krux_binaries#flash-instructions
+ if (device.match(/maixpy_(m5stickv|amigo)/)) {
+ flash.args = ['--verbose', '-B', 'goE', '-b', '1500000']
+ try {
+ const ports = await SerialPort.list()
+
+ // m5stickv and amigo has two ports
+ // get the first
+ let found = false
+ ports.forEach((port) => {
+ if (port.productId == "0403" && !found) {
+ flash.args.push("-p")
+ flash.args.push(port.path)
+ found = true
+ }
+ })
+ } catch (err) {
+ this.send(`${this.name}:error`, { was: 'wipe', done: false , name: err.name, message: err.message, stack: err.stack })
+ }
+ } else if (device.match(/maixpy_(bit|cube)/)) {
+ flash.args = ['--verbose', '-B', 'goE', '-b', '1500000']
+ try {
+ const ports = await SerialPort.list()
+ ports.forEach((port) => {
+ if (port.productId == "0403") {
+ flash.args.push("-p")
+ flash.args.push(port.path)
+ }
+ })
+ } catch (err) {
+ this.send(`${this.name}:error`, { was: 'wipe', done: false , name: err.name, message: err.message, stack: err.stack })
+ }
+ } else if (device.match(/maixpy_dock/g)) {
+ flash.args = ['--verbose', '-B', 'dan', '-b', '1500000']
+ try {
+ const ports = await SerialPort.list()
+ ports.forEach((port) => {
+ if (port.productId == "7523") {
+ flash.args.push("-p")
+ flash.args.push(port.path)
+ }
+ })
+ } catch (err) {
+ this.send(`${this.name}:error`, { was: 'wipe', done: false , name: err.name, message: err.message, stack: err.stack })
+ }
+ } else if (device.match(/maixpy_yahboom/g)){
+ flash.args = ['--verbose', '-B', 'goE', '-b', '1500000']
+ try {
+ const ports = await SerialPort.list()
+ ports.forEach((port) => {
+ if (port.productId == "7523") {
+ flash.args.push("-p")
+ flash.args.push(port.path)
+ }
+ })
+ } catch (error) {
+ this.send(`${this.name}:error`, { was: 'wipe', done: false, name: error.name, message: error.message, stack: error.stack })
+ }
+ } else {
+ const error = new Error()
+ error.name = "Not Implemented Error"
+ error.message = `${device} isnt valid to flash`
+ this.send(`${this.name}:error`, { was: 'wipe', done: false, name: error.name, message: error.message, stack: error.stack })
+ }
+
+ flash.args.push('-E')
+
+ // Choose the correct ktool flasher
+ let globfiles: string[]
+ if (os === 'linux') {
+ globfiles = await glob(`${resources}/**/ktool-linux`)
+ flash.command = globfiles[0]
+ chmod.commands.push({ command: 'chmod', args: ['+x', flash.command] })
+ } else if (os === 'win32') {
+ globfiles = await glob(`${resources}/**/ktool-win.exe`)
+ flash.command = globfiles[0]
+ } else if (os === 'darwin' && !isMac10) {
+ globfiles = await glob(`${resources}/**/ktool-mac`)
+ flash.command = globfiles[0]
+ chmod.commands.push({ command: 'chmod', args: ['+x', flash.command] })
+ } else if (os === 'darwin' && isMac10) {
+ globfiles = await glob(`${resources}/**/ktool-mac-10`)
+ flash.command = globfiles[0]
+ chmod.commands.push({ command: 'chmod', args: ['+x', flash.command] })
+ }
+
+ // stack commands to be executed
+ const promises = chmod.commands.map((cmd) => {
+ return new Promise((resolve, reject) => {
+ let error = null
+ let buffer = Buffer.alloc(0)
+
+ this.send(`${this.name}:data`, `\x1b[32m$> ${cmd.command} ${cmd.args.join(' ')}\x1b[0m\n\n`)
+ const script = spawn(cmd.command, cmd.args)
+
+ script.stdout.on('data', (data) => {
+ buffer = Buffer.concat([buffer, data])
+ this.send(`${this.name}:data`, buffer.toString())
+ })
+
+ script.stderr.on('data', (data) => {
+ buffer = Buffer.concat([buffer, data])
+ this.send(`${this.name}:data`, buffer.toString())
+ error = true
+ })
+
+ script.on('close', (code) => {
+ if (error) {
+ error = new Error(buffer.toString())
+ reject(error)
+ }
+ resolve()
+ })
+ })
+ })
+
+ await Promise.all(promises)
+
+ // setup flash command
+ let flasher = null
+
+ this.send(`${this.name}:data`, `\x1b[32m$> ${flash.command} ${flash.args.join(' ')}\x1b[0m\n\n`)
+
+ if (os === 'linux') {
+ const sudoer = new SudoerLinux()
+ flasher = await sudoer.spawn(flash.command, flash.args.join(' '), { env: process.env })
+ } else if (os === 'darwin') {
+ const sudoer = new SudoerDarwin()
+ flasher = await sudoer.spawn(flash.command, flash.args.join(' '), { env: process.env })
+ } else if (os === 'win32') {
+ flasher = spawn(flash.command, flash.args)
+ }
+
+ let err = null
+ let output = ''
+
+ flasher.stdout.on('data', (data: any) => {
+ output = Buffer.from(data, 'utf-8').toString()
+ if (output.match(/\[ERROR\].*/g)) {
+ output = output.replace("\x1b[31m", "")
+ output = output.replace("\x1b[1m", "")
+ output = output.replace("\x1b[0m", "")
+ output = output.replace("\x1b[32m", "")
+ output = output.replace("\x1b[0m \n", "")
+ output = output.replace("[ERROR]", "")
+ err = new Error(output)
+ }
+ this.send(`${this.name}:data`, output)
+ })
+
+ flasher.stderr.on('data', (data: any) => {
+ output = Buffer.from(data, 'utf-8').toString()
+ err = new Error(output)
+ this.send(`${this.name}:data`, output)
+ })
+
+ flasher.on('close', (code: any) => {
+ if (err) {
+ this.send(`${this.name}:error`, { was: 'wipe', done: false , name: err.name, message: err.message, stack: err.stack })
+ } else {
+ this.send(`${this.name}:success`, { was: 'wipe', done: true })
+ }
+ })
+ })
+ }
+}
diff --git a/package.json b/package.json
index ee1359fb..0af55eec 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "krux-installer",
- "version": "0.0.12",
+ "version": "0.0.13",
"main": "dist-electron/main/index.js",
"description": "Graphical User Interface to download, verify and flash Krux´s firmware on Kendryte K210 hardwares as bitcoin signature devices",
"author": "qlrd <106913782+qlrd@users.noreply.github.com>",
@@ -61,7 +61,6 @@
"chai": "^5.1.0",
"electron": "^29.1.0",
"electron-builder": "^24.4.0",
- "glob": "^10.3.3",
"markdownlint-cli": "^0.39.0",
"mocha": "^10.2.0",
"os-lang": "^3.1.1",
@@ -83,6 +82,7 @@
"command-exists": "^1.2.9",
"debug": "^4.3.4",
"electron-store": "^8.1.0",
+ "glob": "^10.3.3",
"serialport": "^12.0.0",
"vite-plugin-vuetify": "^2.0.1",
"vue-asciimorph": "^0.0.3",
diff --git a/src/App.vue b/src/App.vue
index eb020b9c..f5371a2f 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -32,7 +32,7 @@ import DownloadTestFirmware from './pages/DownloadTestFirmware.vue';
import DownloadTestKboot from './pages/DownloadTestKboot.vue';
import DownloadTestKtool from './pages/DownloadTestKtool.vue';
import FlashToDevice from './pages/FlashToDevice.vue';
-
+import WipeDevice from './pages/WipeDevice.vue';
/**
* Methods: These function will
* manipulate `page` and `data` variables
@@ -53,7 +53,9 @@ import onKruxUnzip from './utils/onKruxUnzip';
import onKruxFlash from './utils/onKruxFlash';
import onKruxFlashData from './utils/onKruxFlashData';
import onKruxUnzipData from './utils/onKruxUnzipData';
-
+import onKruxCheckIfItWillWipeHandler from './utils/onKruxCheckIfItWillWipeHandler';
+import onKruxWipe from './utils/onKruxWipe';
+import onKruxWipeData from './utils/onKruxWipeData';
/**
* Reference for which component will be used as showing page
*/
@@ -94,7 +96,8 @@ const pages: Ref> = shallowRef({
'DownloadTestFirmware': DownloadTestFirmware,
'DownloadTestKboot': DownloadTestKboot,
'DownloadTestKtool': DownloadTestKtool,
- 'FlashToDevice': FlashToDevice
+ 'FlashToDevice': FlashToDevice,
+ 'WipeDevice': WipeDevice
})
/**
@@ -114,14 +117,17 @@ window.api.onSuccess('krux:store:set', onKruxStoreSet(data));
window.api.onSuccess('krux:verify:releases:fetch', onKruxVerifyReleasesFetch(data));
window.api.onSuccess('krux:check:resource', onKruxCheckResources(data));
window.api.onSuccess('krux:check:will:flash', onKruxCheckIfItWillFlashHandler(data));
+window.api.onSuccess('krux:check:will:wipe', onKruxCheckIfItWillWipeHandler(data));
window.api.onSuccess('krux:download:resources', onKruxDownloadResources(data));
window.api.onSuccess('krux:verify:releases:hash', onKruxVerifyReleasesHash(data));
window.api.onSuccess('krux:verify:releases:sign', onKruxVerifyReleaseSign(data));
window.api.onSuccess('krux:unzip', onKruxUnzip(data));
window.api.onSuccess('krux:flash', onKruxFlash(data));
+window.api.onSuccess('krux:wipe', onKruxWipe(data));
window.api.onData('krux:download:resources', onKruxDownloadResourcesData(data));
window.api.onData('krux:unzip', onKruxUnzipData(data));
window.api.onData('krux:flash', onKruxFlashData(data));
+window.api.onData('krux:wipe', onKruxWipeData(data));
window.api.onError('krux:change:page', onError(data));
window.api.onError('krux:store:get', onError(data));
window.api.onError('krux:store:set', onError(data));
@@ -130,6 +136,7 @@ window.api.onError('krux:verify:releases:fetch', onError(data));
window.api.onError('krux:check:resource',onError(data));
window.api.onError('krux:download:resources', onError(data));
window.api.onError('krux:flash', onError(data));
+window.api.onError('krux:wipe', onError(data));
window.api.onError('krux:unzip', onError(data));
/**
diff --git a/src/pages/FlashToDevice.vue b/src/pages/FlashToDevice.vue
index 92628894..419ae137 100644
--- a/src/pages/FlashToDevice.vue
+++ b/src/pages/FlashToDevice.vue
@@ -59,7 +59,6 @@ const allOutput: Ref = ref('')
Methods
*/
async function backToFn () {
- output.value = output.value.split(' ').splice(0).join('')
await window.api.invoke('krux:store:get', { from: 'FlashToDevice', keys: ['device', 'version', 'os', 'isMac10', 'showFlash'] })
}
@@ -68,8 +67,7 @@ async function exitAppFn () {
}
onMounted(async function () {
- allOutput.value = allOutput.value.split(' ').splice(0).join('')
- await window.api.invoke('krux:unzip')
+ await window.api.invoke('krux:unzip', { will: 'flash' })
})
watch(output, function(newValue) {
diff --git a/src/pages/Main.vue b/src/pages/Main.vue
index 414b95d6..240435af 100644
--- a/src/pages/Main.vue
+++ b/src/pages/Main.vue
@@ -44,6 +44,24 @@
+
+
+
+
+
+ {{ wipe }}
+
+
+
+
+
@@ -75,6 +93,7 @@ const props = defineProps<{
os: string,
isMac10: boolean,
showFlash: boolean,
+ showWipe: boolean,
clickMessage: string
}>()
@@ -108,11 +127,28 @@ const flash = computed(() => {
}
})
+const wipe = computed(() => {
+ if (props.os === 'linux') {
+ return 'Wipe with ktool-linux'
+ }
+ else if (props.os === 'win32') {
+ return 'Wipe with ktool-win.exe'
+ }
+ else if (props.os === 'darwin' && !props.isMac10) {
+ return 'Wipe with ktool-mac'
+ }
+ else if (props.os === 'darwin' && props.isMac10) {
+ return 'Wipe with ktool-mac-10'
+ }
+ else {
+ return 'Wipe'
+ }
+})
/**
*Variables
*/
-const { showFlash } = toRefs(props)
+const { showFlash, showWipe } = toRefs(props)
/**
@@ -130,7 +166,25 @@ async function flashDevice () {
await window.api.invoke('krux:change:page', { page: 'FlashToDevice' })
}
+async function wipeDevice () {
+ const message = [
+ "\t\t\t\t\tWARNING: CRITICAL OPERATION",
+ "",
+ "You are about to initiate a FULL WIPE of this device. This operation will:",
+ "",
+ "- Permanently erase all saved data.",
+ "- Remove the existing firmware.",
+ "- Render the device non-functional until new firmware is re-flashed."
+ ].join("\n")
+
+ const confirmed = confirm(message)
+ if (confirmed) {
+ await window.api.invoke('krux:change:page', { page: 'WipeDevice' })
+ }
+}
+
onMounted(async function () {
+ await window.api.invoke('krux:check:will:wipe')
await window.api.invoke('krux:check:will:flash')
})
-
\ No newline at end of file
+
diff --git a/src/pages/WipeDevice.vue b/src/pages/WipeDevice.vue
new file mode 100644
index 00000000..d492d03b
--- /dev/null
+++ b/src/pages/WipeDevice.vue
@@ -0,0 +1,89 @@
+
+
+
+
+
+
+
+ {{ !done ? 'Wiping...' : 'Do not trust, verify! ' }}
+ {{ !done ? 'Do not unplug device or shutdown computer!' : 'Before quit:' }}
+ {{ !done ? 'It may take a while to complete.' : '(1) Scroll down the output to check what happened to your device;' }}
+ {{ !done ? '' : '(2) shutdown your device and unplug it' }}
+
+
+
+
+
+
+
+
+
+ Back
+
+
+
+
+ Quit
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/utils/messages.ts b/src/utils/messages.ts
index 4e81dad7..480c9704 100644
--- a/src/utils/messages.ts
+++ b/src/utils/messages.ts
@@ -15,6 +15,8 @@ async function add(
function clean(data: Ref>): void {
data.value.messages = []
data.value.indexes = []
+ data.value.output = ""
+ data.value.done = false
}
async function close(data: Ref>): Promise {
@@ -24,4 +26,4 @@ async function close(data: Ref>): Promise {
}
}
-export default { add, clean, close }
\ No newline at end of file
+export default { add, clean, close }
diff --git a/src/utils/onError.ts b/src/utils/onError.ts
index d0a4c7b1..3077178b 100644
--- a/src/utils/onError.ts
+++ b/src/utils/onError.ts
@@ -11,6 +11,9 @@ export default function (data: Ref>): Function {
...result,
backTo: 'Main'
}
+ if (data.value.output) {
+ data.value.output = ""
+ }
await window.api.invoke('krux:change:page', { page: 'ErrorMsg' })
}
-}
\ No newline at end of file
+}
diff --git a/src/utils/onKruxCheckIfItWillFlashHandler.ts b/src/utils/onKruxCheckIfItWillFlashHandler.ts
index b34c36a1..b3f2c2d1 100644
--- a/src/utils/onKruxCheckIfItWillFlashHandler.ts
+++ b/src/utils/onKruxCheckIfItWillFlashHandler.ts
@@ -1,29 +1,40 @@
import { Ref } from "vue"
+function wipeOrFlash(data: Ref>, kind: string): string {
+ let click = ''
+ if (data.value.os === 'linux') {
+ click = `${kind} with ktool-linux`
+ }
+ else if (data.value.os === 'win32') {
+ click = `${kind} with ktool-win.exe`
+ }
+ else if (data.value.os === 'darwin' && !data.value.isMac10) {
+ click = `${kind} with ktool-mac`
+ }
+ else if (data.value.os === 'darwin' && data.value.isMac10) {
+ click = `${kind} with ktool-mac-10`
+ }
+ return click
+}
+
export default function (data: Ref>): Function {
return function (_: Event, result: Record<'showFlash', boolean>): void {
data.value.showFlash = result.showFlash
if (!data.value.showFlash && data.value.device !== 'Select device') {
if (data.value.version === 'Select version') {
- data.value.clickMessage = `Please click 'Select version' to download sources`
+ if(data.value.showWipe) {
+ const click = wipeOrFlash(data, 'Wipe')
+ data.value.clickMessage = `Click 'Select version' or '${click}'`
+ } else {
+ data.value.clickMessage = `Click 'Select version'`
+ }
} else {
- data.value.clickMessage = `Please click 'Version: ${data.value.version}' to download sources for ${data.value.device}`
+ const click = wipeOrFlash(data, 'Wipe')
+ data.value.clickMessage = `Click 'Version: ${data.value.version}' or ${click} for ${data.value.device}`
}
} else {
- let click = ''
- if (data.value.os === 'linux') {
- click = 'Flash with ktool-linux'
- }
- else if (data.value.os === 'win32') {
- click = 'Flash with ktool-win.exe'
- }
- else if (data.value.os === 'darwin' && !data.value.isMac10) {
- click = 'Flash with ktool-mac'
- }
- else if (data.value.os === 'darwin' && data.value.isMac10) {
- click = 'Flash with ktool-mac-10'
- }
+ const click = wipeOrFlash(data, 'Wipe/Flash')
data.value.clickMessage = `Connect your ${data.value.device} device and power on it before click '${click}'`
}
}
-}
\ No newline at end of file
+}
diff --git a/src/utils/onKruxCheckIfItWillWipeHandler.ts b/src/utils/onKruxCheckIfItWillWipeHandler.ts
new file mode 100644
index 00000000..fec6707d
--- /dev/null
+++ b/src/utils/onKruxCheckIfItWillWipeHandler.ts
@@ -0,0 +1,24 @@
+import { Ref } from "vue"
+
+function wipeOrFlash(data: Ref>, kind: string): string {
+ let click = ''
+ if (data.value.os === 'linux') {
+ click = `${kind} with ktool-linux`
+ }
+ else if (data.value.os === 'win32') {
+ click = `${kind} with ktool-win.exe`
+ }
+ else if (data.value.os === 'darwin' && !data.value.isMac10) {
+ click = `${kind} with ktool-mac`
+ }
+ else if (data.value.os === 'darwin' && data.value.isMac10) {
+ click = `${kind} with ktool-mac-10`
+ }
+ return click
+}
+
+export default function (data: Ref>): Function {
+ return function (_: Event, result: Record<'showWipe', boolean>): void {
+ data.value.showWipe = result.showWipe
+ }
+}
diff --git a/src/utils/onKruxFlash.ts b/src/utils/onKruxFlash.ts
index 84956de0..d67c94fd 100644
--- a/src/utils/onKruxFlash.ts
+++ b/src/utils/onKruxFlash.ts
@@ -8,5 +8,6 @@ export default function (
result:Record
): void {
data.value.done = result.done
+ data.value.output = ""
}
-}
\ No newline at end of file
+}
diff --git a/src/utils/onKruxStoreGet.ts b/src/utils/onKruxStoreGet.ts
index 87bd7652..65e29f26 100644
--- a/src/utils/onKruxStoreGet.ts
+++ b/src/utils/onKruxStoreGet.ts
@@ -292,11 +292,11 @@ export default function onKruxStoreGet (data: Ref>): Functio
await setMainData(data, result)
}
- if (result.from === 'FlashToDevice') {
+ if (result.from === 'FlashToDevice' || result.from === 'WipeDevice') {
messages.clean(data)
await window.api.invoke('krux:change:page', { page: 'Main' })
setMainData(data, result)
}
}
-}
\ No newline at end of file
+}
diff --git a/src/utils/onKruxUnzip.ts b/src/utils/onKruxUnzip.ts
index 5c7b96d6..7b0d586f 100644
--- a/src/utils/onKruxUnzip.ts
+++ b/src/utils/onKruxUnzip.ts
@@ -10,8 +10,16 @@ export default function (
): Function {
return async function (
_: Event,
- result:string
+ result:Record<'will', string>
): Promise{
- await window.api.invoke('krux:flash')
+ console.log("DATA===============")
+ console.log(data)
+ console.log("RESULT===============")
+ console.log(result)
+ if (result.will == 'flash') {
+ await window.api.invoke('krux:flash')
+ } else if (result.will == 'wipe') {
+ await window.api.invoke('krux:wipe')
+ }
}
}
diff --git a/src/utils/onKruxWipe.ts b/src/utils/onKruxWipe.ts
new file mode 100644
index 00000000..d67c94fd
--- /dev/null
+++ b/src/utils/onKruxWipe.ts
@@ -0,0 +1,13 @@
+import { Ref } from "vue";
+
+export default function (
+ data: Ref>
+): Function {
+ return function (
+ _: Event,
+ result:Record
+ ): void {
+ data.value.done = result.done
+ data.value.output = ""
+ }
+}
diff --git a/src/utils/onKruxWipeData.ts b/src/utils/onKruxWipeData.ts
new file mode 100644
index 00000000..79df67a9
--- /dev/null
+++ b/src/utils/onKruxWipeData.ts
@@ -0,0 +1,27 @@
+import { Ref } from "vue";
+
+// If you have no problems simply ignoring all type-checking features for this library, you have two options:
+// Add @ts-ignore above all imports or Create a declaration file with any type, so all imports are automatically considered to be of any type.
+// see https://stackoverflow.com/questions/56688893/how-to-use-a-module-when-it-could-not-find-a-declaration-file#answer-56690386
+// @ts-ignore
+import { AnsiUp } from 'ansi_up'
+
+/**
+ * Stream shell output to web frontend
+ * @see https://www.appsloveworld.com/vuejs/100/8/stream-shell-output-to-web-front-end
+ * @param data
+ */
+export default function (
+ data: Ref>
+): Function {
+ return function (
+ _: Event,
+ result:string
+ ): void {
+ const ansi = new AnsiUp()
+ let tmp = result.replace(/%\s/, "\n")
+ tmp = tmp.replace(/kiB\/s/g, "kiB/s\n")
+
+ data.value.output = ansi.ansi_to_html(tmp).replace(/\n/gm, '
')
+ }
+}
diff --git a/test/e2e/specs/002.app-startup.spec.mts b/test/e2e/specs/002.app-startup.spec.mts
index 24212c5b..de838cf4 100644
--- a/test/e2e/specs/002.app-startup.spec.mts
+++ b/test/e2e/specs/002.app-startup.spec.mts
@@ -22,7 +22,7 @@ describe('KruxInstaller start up', () => {
const version = await browser.electron.execute(function (electron) {
return electron.app.getVersion()
})
- expect(version).to.be.equal('0.0.12')
+ expect(version).to.be.equal('0.0.13')
})
})
diff --git a/test/e2e/specs/038-verified-official-release.spec.mts b/test/e2e/specs/038-verified-official-release.spec.mts
index 1387635b..502a0b48 100644
--- a/test/e2e/specs/038-verified-official-release.spec.mts
+++ b/test/e2e/specs/038-verified-official-release.spec.mts
@@ -7,7 +7,7 @@ import { createRequire } from 'module'
const App = createRequire(import.meta.url)('../pageobjects/app.page')
-const SHA256 = "e9 b1 56 d4 d0 1e 80 17 ed 4f 2f ad ac 01 cb 07 fe b2 7e 8a 01 e3 c9 7e 01 9c f2 f9 03 86 e6 b2"
+const SHA256 = "f2 54 69 2f 76 6d c6 b0 09 c8 ca 7f 43 b6 74 d0 88 06 26 85 bb 20 3b 85 0f 8b 70 2f 64 1b 59 35"
describe('KruxInstaller VerifiedOfficialRelease page (show and click back button)', () => {
let instance: any;