diff --git a/lib/gui/app/components/source-selector/source-selector.tsx b/lib/gui/app/components/source-selector/source-selector.tsx index 0215957c..fbf3d963 100644 --- a/lib/gui/app/components/source-selector/source-selector.tsx +++ b/lib/gui/app/components/source-selector/source-selector.tsx @@ -266,17 +266,6 @@ export class SourceSelector extends React.Component< hasMBR: boolean; }, ) { - if (!supportedFormats.isSupportedImage(image.path)) { - const invalidImageError = errors.createUserError({ - title: 'Invalid image', - description: messages.error.invalidImage(image.path), - }); - - osDialog.showError(invalidImageError); - analytics.logEvent('Invalid image', image); - return; - } - try { let message = null; let title = null; @@ -321,16 +310,6 @@ export class SourceSelector extends React.Component< } catch (error) { analytics.logException(error); } - if (!supportedFormats.isSupportedImage(imagePath)) { - const invalidImageError = errors.createUserError({ - title: 'Invalid image', - description: messages.error.invalidImage(imagePath), - }); - - osDialog.showError(invalidImageError); - analytics.logEvent('Invalid image', { path: imagePath }); - return; - } let source; if (SourceType === sourceDestination.File) { @@ -460,9 +439,8 @@ export class SourceSelector extends React.Component< const hasImage = selectionState.hasImage(); - const imageBasename = hasImage - ? path.basename(selectionState.getImagePath()) - : ''; + const imagePath = selectionState.getImagePath(); + const imageBasename = hasImage ? path.basename(imagePath) : ''; const imageName = selectionState.getImageName(); const imageSize = selectionState.getImageSize(); @@ -487,7 +465,7 @@ export class SourceSelector extends React.Component< {middleEllipsis(imageName || imageBasename, 20)} @@ -554,21 +532,28 @@ export class SourceSelector extends React.Component< {showImageDetails && ( { this.setState({ showImageDetails: false }); }} > - {selectionState.getImagePath()} + + Name: + {imageName || imageBasename} + + + Path: + {imagePath} + )} {showURLSelector && ( { + done={async (imageURL: string) => { // Avoid analytics and selection state changes // if no file was resolved from the dialog. - if (!imagePath) { + if (!imageURL) { analytics.logEvent('URL selector closed'); this.setState({ showURLSelector: false, @@ -577,7 +562,7 @@ export class SourceSelector extends React.Component< } await this.selectImageByPath({ - imagePath, + imagePath: imageURL, SourceType: sourceDestination.Http, }); this.setState({ diff --git a/lib/gui/app/models/store.ts b/lib/gui/app/models/store.ts index 1d8ff2e9..d66e9a73 100644 --- a/lib/gui/app/models/store.ts +++ b/lib/gui/app/models/store.ts @@ -21,8 +21,6 @@ import { v4 as uuidV4 } from 'uuid'; import * as constraints from '../../../shared/drive-constraints'; import * as errors from '../../../shared/errors'; -import * as fileExtensions from '../../../shared/file-extensions'; -import * as supportedFormats from '../../../shared/supported-formats'; import * as utils from '../../../shared/utils'; import * as settings from './settings'; @@ -402,51 +400,6 @@ function storeReducer( }); } - if (!_.isString(action.data.extension)) { - throw errors.createError({ - title: `Invalid image extension: ${action.data.extension}`, - }); - } - - const extension = _.toLower(action.data.extension); - - if (!_.includes(supportedFormats.getAllExtensions(), extension)) { - throw errors.createError({ - title: `Invalid image extension: ${action.data.extension}`, - }); - } - - let lastImageExtension = fileExtensions.getLastFileExtension( - action.data.path, - ); - lastImageExtension = _.isString(lastImageExtension) - ? _.toLower(lastImageExtension) - : lastImageExtension; - - if (lastImageExtension !== extension) { - if (!_.isString(action.data.archiveExtension)) { - throw errors.createError({ - title: 'Missing image archive extension', - }); - } - - const archiveExtension = _.toLower(action.data.archiveExtension); - - if ( - !_.includes(supportedFormats.getAllExtensions(), archiveExtension) - ) { - throw errors.createError({ - title: `Invalid image archive extension: ${action.data.archiveExtension}`, - }); - } - - if (lastImageExtension !== archiveExtension) { - throw errors.createError({ - title: `Image archive extension mismatch: ${action.data.archiveExtension} and ${lastImageExtension}`, - }); - } - } - const MINIMUM_IMAGE_SIZE = 0; if (action.data.size !== undefined) { diff --git a/lib/shared/file-extensions.ts b/lib/shared/file-extensions.ts deleted file mode 100644 index 48ec778f..00000000 --- a/lib/shared/file-extensions.ts +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2017 balena.io - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import * as _ from 'lodash'; -import { lookup } from 'mime-types'; - -/** - * @summary Get the extensions of a file - * - * @example - * const extensions = fileExtensions.getFileExtensions('path/to/foo.img.gz'); - * console.log(extensions); - * > [ 'img', 'gz' ] - */ -export function getFileExtensions(filePath: string): string[] { - return _.chain(filePath).split('.').tail().map(_.toLower).value(); -} - -/** - * @summary Get the last file extension - * - * @example - * const extension = fileExtensions.getLastFileExtension('path/to/foo.img.gz'); - * console.log(extension); - * > 'gz' - */ -export function getLastFileExtension(filePath: string): string | null { - return _.last(getFileExtensions(filePath)) || null; -} - -/** - * @summary Get the penultimate file extension - * - * @example - * const extension = fileExtensions.getPenultimateFileExtension('path/to/foo.img.gz'); - * console.log(extension); - * > 'img' - */ -export function getPenultimateFileExtension(filePath: string): string | null { - const extensions = getFileExtensions(filePath); - if (extensions.length >= 2) { - const ext = extensions[extensions.length - 2]; - return lookup(ext) ? ext : null; - } - return null; -} diff --git a/lib/shared/messages.ts b/lib/shared/messages.ts index 50482f17..3e23d34d 100644 --- a/lib/shared/messages.ts +++ b/lib/shared/messages.ts @@ -143,10 +143,6 @@ export const error = { ].join(' '); }, - invalidImage: (imagePath: string) => { - return `${imagePath} is not a supported image type.`; - }, - openImage: (imageBasename: string, errorMessage: string) => { return [ `Something went wrong while opening ${imageBasename}\n\n`, diff --git a/lib/shared/supported-formats.ts b/lib/shared/supported-formats.ts index b9089f3b..4dee3ba5 100644 --- a/lib/shared/supported-formats.ts +++ b/lib/shared/supported-formats.ts @@ -15,15 +15,9 @@ */ import * as sdk from 'etcher-sdk'; -import * as _ from 'lodash'; import * as mime from 'mime-types'; import * as path from 'path'; -import { - getLastFileExtension, - getPenultimateFileExtension, -} from './file-extensions'; - export function getCompressedExtensions(): string[] { const result = []; for (const [ @@ -57,34 +51,6 @@ export function getAllExtensions(): string[] { ]; } -export function isSupportedImage(imagePath: string): boolean { - const lastExtension = getLastFileExtension(imagePath); - const penultimateExtension = getPenultimateFileExtension(imagePath); - - if ( - _.some([ - _.includes(getNonCompressedExtensions(), lastExtension), - _.includes(getArchiveExtensions(), lastExtension), - ]) - ) { - return true; - } - - if ( - _.every([ - _.includes(getCompressedExtensions(), lastExtension), - _.includes(getNonCompressedExtensions(), penultimateExtension), - ]) - ) { - return true; - } - - return ( - _.isNil(penultimateExtension) && - _.includes(getCompressedExtensions(), lastExtension) - ); -} - export function looksLikeWindowsImage(imagePath: string): boolean { const regex = /windows|win7|win8|win10|winxp/i; return regex.test(path.basename(imagePath)); diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index d2388313..be8fca0b 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -696,9 +696,9 @@ "dev": true }, "@types/fs-extra": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-8.1.1.tgz", - "integrity": "sha512-TcUlBem321DFQzBNuz8p0CLLKp0VvF/XH9E4KHNmgwyp4E3AfgI5cjiIVZWlbfThBop2qxFIh4+LeY6hVWWZ2w==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.1.tgz", + "integrity": "sha512-B42Sxuaz09MhC3DDeW5kubRcQ5by4iuVQ0cRRWM2lggLzAa/KVom0Aft/208NgMvNQQZ86s5rVcqDdn/SH0/mg==", "dev": true, "requires": { "@types/node": "*" @@ -1002,14 +1002,6 @@ "dev": true, "requires": { "@types/node": "*" - }, - "dependencies": { - "@types/node": { - "version": "14.0.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.0.1.tgz", - "integrity": "sha512-FAYBGwC+W6F9+huFIDtn43cpy7+SzG+atzRiTfdp3inUKL2hXnd4rG8hylJLIh4+hqrQy1P17kvJByE/z825hA==", - "dev": true - } } }, "@types/uuid": { @@ -1438,12 +1430,6 @@ "integrity": "sha512-/FQM1EDkTsf63Ub2C6O7GuYFDsSXUwsaZDurV0np41ocwq0jthUAYCmhBX9f+KwlaCgIuWyr/4WlUQUBfKfZog==", "dev": true }, - "any-promise": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=", - "dev": true - }, "anymatch": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", @@ -1461,26 +1447,26 @@ "dev": true }, "app-builder-lib": { - "version": "22.6.1", - "resolved": "https://registry.npmjs.org/app-builder-lib/-/app-builder-lib-22.6.1.tgz", - "integrity": "sha512-ENL7r+H7IBfDb4faeLASgndsXrAT7AV7m7yJjcpbFDXYma6an7ZWGFIvR0HJrsfiC5TIB8kdLJ/aMSImrrSi/Q==", + "version": "22.7.0", + "resolved": "https://registry.npmjs.org/app-builder-lib/-/app-builder-lib-22.7.0.tgz", + "integrity": "sha512-blRKwV8h0ztualXS50ciCTo39tbuDGNS+ldcy8+KLvKXuT6OpYnSJ7M6MSfPT+xWatshMHJV1rJx3Tl+k/Sn/g==", "dev": true, "requires": { "7zip-bin": "~5.0.3", "@develar/schema-utils": "~2.6.5", "async-exit-hook": "^2.0.1", "bluebird-lst": "^1.0.9", - "builder-util": "22.6.1", - "builder-util-runtime": "8.7.0", + "builder-util": "22.7.0", + "builder-util-runtime": "8.7.1", "chromium-pickle-js": "^0.2.0", - "debug": "^4.1.1", - "ejs": "^3.1.2", - "electron-publish": "22.6.1", + "debug": "^4.2.0", + "ejs": "^3.1.3", + "electron-publish": "22.7.0", "fs-extra": "^9.0.0", "hosted-git-info": "^3.0.4", "is-ci": "^2.0.0", "isbinaryfile": "^4.0.6", - "js-yaml": "^3.13.1", + "js-yaml": "^3.14.0", "lazy-val": "^1.0.4", "minimatch": "^3.0.4", "normalize-package-data": "^2.5.0", @@ -1488,6 +1474,28 @@ "sanitize-filename": "^1.6.3", "semver": "^7.3.2", "temp-file": "^3.3.7" + }, + "dependencies": { + "builder-util-runtime": { + "version": "8.7.1", + "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-8.7.1.tgz", + "integrity": "sha512-uEBH1nAnTvzjcsrh2XI3qOzJ39h0+9kuIuwj+kCc3a07TZNGShfJcai8fFzL3mNgGjEFxoq+XMssR11r+FOFSg==", + "dev": true, + "requires": { + "debug": "^4.2.0", + "sax": "^1.2.4" + } + }, + "js-yaml": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", + "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + } } }, "apple-data-compression": { @@ -2300,22 +2308,22 @@ "dev": true }, "builder-util": { - "version": "22.6.1", - "resolved": "https://registry.npmjs.org/builder-util/-/builder-util-22.6.1.tgz", - "integrity": "sha512-A9cF+bSHqRTSKIUHEyE92Tl0Uh12N7yZRH9bccIL3gRUwtp6ulF28LsjNIWTSQ1clZo2M895cT5PCrKzjPQFVg==", + "version": "22.7.0", + "resolved": "https://registry.npmjs.org/builder-util/-/builder-util-22.7.0.tgz", + "integrity": "sha512-UV3MKL0mwjMq2y9JlBf28Cegpj0CrIXcjGkO0TXn+QZ6Yy9rY6lHOuUvpQ19ct2Qh1o+QSwH3Q1nKUf5viJBBg==", "dev": true, "requires": { "7zip-bin": "~5.0.3", "@types/debug": "^4.1.5", - "@types/fs-extra": "^8.1.0", + "@types/fs-extra": "^9.0.1", "app-builder-bin": "3.5.9", "bluebird-lst": "^1.0.9", - "builder-util-runtime": "8.7.0", + "builder-util-runtime": "8.7.1", "chalk": "^4.0.0", - "debug": "^4.1.1", + "debug": "^4.2.0", "fs-extra": "^9.0.0", "is-ci": "^2.0.0", - "js-yaml": "^3.13.1", + "js-yaml": "^3.14.0", "source-map-support": "^0.5.19", "stat-mode": "^1.0.0", "temp-file": "^3.3.7" @@ -2331,6 +2339,16 @@ "color-convert": "^2.0.1" } }, + "builder-util-runtime": { + "version": "8.7.1", + "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-8.7.1.tgz", + "integrity": "sha512-uEBH1nAnTvzjcsrh2XI3qOzJ39h0+9kuIuwj+kCc3a07TZNGShfJcai8fFzL3mNgGjEFxoq+XMssR11r+FOFSg==", + "dev": true, + "requires": { + "debug": "^4.2.0", + "sax": "^1.2.4" + } + }, "chalk": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.0.0.tgz", @@ -2362,6 +2380,16 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, + "js-yaml": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", + "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, "supports-color": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", @@ -4177,16 +4205,16 @@ } }, "dmg-builder": { - "version": "22.6.1", - "resolved": "https://registry.npmjs.org/dmg-builder/-/dmg-builder-22.6.1.tgz", - "integrity": "sha512-jUTN0acP15puzevtQASj7QEPgUGpedWSuSnOwR/++JbeYRTwU2oro09h/KZnaeMcxgxjdmT3tYLJeY1XUfPbRg==", + "version": "22.7.0", + "resolved": "https://registry.npmjs.org/dmg-builder/-/dmg-builder-22.7.0.tgz", + "integrity": "sha512-5Ea2YEz6zSNbyGzZD+O9/MzmaXb6oa15cSKWo4JQ1xP4rorOpte7IOj2jcwYjtc+Los2gu1lvT314OC1OZIWgg==", "dev": true, "requires": { - "app-builder-lib": "22.6.1", - "builder-util": "22.6.1", + "app-builder-lib": "22.7.0", + "builder-util": "22.7.0", "fs-extra": "^9.0.0", "iconv-lite": "^0.5.1", - "js-yaml": "^3.13.1", + "js-yaml": "^3.14.0", "sanitize-filename": "^1.6.3" }, "dependencies": { @@ -4198,6 +4226,16 @@ "requires": { "safer-buffer": ">= 2.1.2 < 3" } + }, + "js-yaml": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", + "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } } } }, @@ -4275,14 +4313,13 @@ "dev": true }, "drivelist": { - "version": "8.0.10", - "resolved": "https://registry.npmjs.org/drivelist/-/drivelist-8.0.10.tgz", - "integrity": "sha512-2A/NCMn9jQ/9J1B8zohS8rnXQKDM6ZixLAlYS/rBeZV2NuSXJCMr/M8kKdr4vy95oOxKXi8NXk+IVrHCS3bung==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/drivelist/-/drivelist-9.0.0.tgz", + "integrity": "sha512-DNQ1oFAv5p1+UKVkQHCYQFHolFbItxSnjcJchxrhlEkW4RSuLfC0xOnq87uM8dcMzOuPfA37SKX7HsUIpw14uA==", "dev": true, "requires": { "bindings": "^1.3.0", "debug": "^3.1.0", - "mz": "^2.7.0", "nan": "^2.14.0", "prebuild-install": "^5.2.4" }, @@ -4364,18 +4401,18 @@ } }, "electron-builder": { - "version": "22.6.1", - "resolved": "https://registry.npmjs.org/electron-builder/-/electron-builder-22.6.1.tgz", - "integrity": "sha512-3/VNg9GfXKHM53TilFtfF1+bsAR8THK1XHgeqCpsiequa02J9jTPc/DhpCUKQPkrs6/EIGxP7uboop7XYoew0Q==", + "version": "22.7.0", + "resolved": "https://registry.npmjs.org/electron-builder/-/electron-builder-22.7.0.tgz", + "integrity": "sha512-t6E3oMutpST64YWbZCg7HodEwJOsnjUF1vnDIHm2MW6CFZPX8tlCK6efqaV66LU0E0Nkp/JH6TE5bCqQ1+VdPQ==", "dev": true, "requires": { "@types/yargs": "^15.0.5", - "app-builder-lib": "22.6.1", + "app-builder-lib": "22.7.0", "bluebird-lst": "^1.0.9", - "builder-util": "22.6.1", - "builder-util-runtime": "8.7.0", + "builder-util": "22.7.0", + "builder-util-runtime": "8.7.1", "chalk": "^4.0.0", - "dmg-builder": "22.6.1", + "dmg-builder": "22.7.0", "fs-extra": "^9.0.0", "is-ci": "^2.0.0", "lazy-val": "^1.0.4", @@ -4395,6 +4432,16 @@ "color-convert": "^2.0.1" } }, + "builder-util-runtime": { + "version": "8.7.1", + "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-8.7.1.tgz", + "integrity": "sha512-uEBH1nAnTvzjcsrh2XI3qOzJ39h0+9kuIuwj+kCc3a07TZNGShfJcai8fFzL3mNgGjEFxoq+XMssR11r+FOFSg==", + "dev": true, + "requires": { + "debug": "^4.2.0", + "sax": "^1.2.4" + } + }, "chalk": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.0.0.tgz", @@ -4535,15 +4582,15 @@ } }, "electron-publish": { - "version": "22.6.1", - "resolved": "https://registry.npmjs.org/electron-publish/-/electron-publish-22.6.1.tgz", - "integrity": "sha512-/MkS47ospdSfAFW5Jp52OzYou14HhGJpZ51uAc3GJ5rCfACeqpimC/n1ajRLE3hcXxTWfd3t9MCuClq5jrUO5w==", + "version": "22.7.0", + "resolved": "https://registry.npmjs.org/electron-publish/-/electron-publish-22.7.0.tgz", + "integrity": "sha512-hmU69xlb6vvAV3QfpHYDlkdZMFdBAgDbptoxbLFrnTq5bOkcL8AaDbvxeoZ4+lvqgs29NwqGpkHo2oN+p/hCfg==", "dev": true, "requires": { - "@types/fs-extra": "^8.1.0", + "@types/fs-extra": "^9.0.1", "bluebird-lst": "^1.0.9", - "builder-util": "22.6.1", - "builder-util-runtime": "8.7.0", + "builder-util": "22.7.0", + "builder-util-runtime": "8.7.1", "chalk": "^4.0.0", "fs-extra": "^9.0.0", "lazy-val": "^1.0.4", @@ -4560,6 +4607,16 @@ "color-convert": "^2.0.1" } }, + "builder-util-runtime": { + "version": "8.7.1", + "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-8.7.1.tgz", + "integrity": "sha512-uEBH1nAnTvzjcsrh2XI3qOzJ39h0+9kuIuwj+kCc3a07TZNGShfJcai8fFzL3mNgGjEFxoq+XMssR11r+FOFSg==", + "dev": true, + "requires": { + "debug": "^4.2.0", + "sax": "^1.2.4" + } + }, "chalk": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.0.0.tgz", @@ -5083,9 +5140,9 @@ "dev": true }, "etcher-sdk": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/etcher-sdk/-/etcher-sdk-4.1.3.tgz", - "integrity": "sha512-lwTAHTxchkXGX7T3+zPIuZBNs2+j2Gtoryb4A2nBfrfd0l5mjmTY/UO8T6cI0YuZDN6XDMwwiF+riDzynXnBTA==", + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/etcher-sdk/-/etcher-sdk-4.1.4.tgz", + "integrity": "sha512-s9KXeLOtwrOxZs6F2VpGdS2VARwgJzmQp7/Xh4DG0yTAIR58djzZ2+cmUQQN16ztFMiQdCgTWWnOUJV1eVtO4g==", "dev": true, "requires": { "@ronomon/direct-io": "^3.0.1", @@ -5095,7 +5152,7 @@ "check-disk-space": "^2.1.0", "crc": "^3.8.0", "debug": "^3.1.0", - "drivelist": "^8.0.4", + "drivelist": "^9.0.0", "file-disk": "^6.0.1", "file-type": "^8.0.0", "lodash": "^4.17.10", @@ -9079,17 +9136,6 @@ "integrity": "sha1-j7+rsKmKJT0xhDMfno3rc3L6xsA=", "dev": true }, - "mz": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", - "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", - "dev": true, - "requires": { - "any-promise": "^1.0.0", - "object-assign": "^4.0.1", - "thenify-all": "^1.0.0" - } - }, "nan": { "version": "2.14.1", "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.1.tgz", @@ -9137,9 +9183,9 @@ } }, "needle": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/needle/-/needle-2.4.1.tgz", - "integrity": "sha512-x/gi6ijr4B7fwl6WYL9FwlCvRQKGlUNvnceho8wxkwXqN8jvVmmmATTmZPRRG7b/yC1eode26C2HO9jl78Du9g==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/needle/-/needle-2.5.0.tgz", + "integrity": "sha512-o/qITSDR0JCyCKEQ1/1bnUXMmznxabbwi/Y4WwJElf+evwJNFNwIDMCCt5IigFVxgeGBJESLohGtIS9gEzo1fA==", "dev": true, "requires": { "debug": "^3.2.6", @@ -9199,9 +9245,9 @@ } }, "node-abi": { - "version": "2.16.0", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.16.0.tgz", - "integrity": "sha512-+sa0XNlWDA6T+bDLmkCUYn6W5k5W6BPRL6mqzSCs6H/xUgtl4D5x2fORKDzopKiU6wsyn/+wXlRXwXeSp+mtoA==", + "version": "2.17.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.17.0.tgz", + "integrity": "sha512-dFRAA0ACk/aBo0TIXQMEWMLUTyWYYT8OBYIzLmEUrQTElGRjxDCvyBZIsDL0QA7QCaj9PrawhOmTEdsuLY4uOQ==", "dev": true, "requires": { "semver": "^5.4.1" @@ -10186,15 +10232,15 @@ "dev": true }, "prebuild-install": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-5.3.3.tgz", - "integrity": "sha512-GV+nsUXuPW2p8Zy7SarF/2W/oiK8bFQgJcncoJ0d7kRpekEA0ftChjfEaF9/Y+QJEc/wFR7RAEa8lYByuUIe2g==", + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-5.3.4.tgz", + "integrity": "sha512-AkKN+pf4fSEihjapLEEj8n85YIw/tN6BQqkhzbDc0RvEZGdkpJBGMUYx66AAMcPG2KzmPQS7Cm16an4HVBRRMA==", "dev": true, "requires": { "detect-libc": "^1.0.3", "expand-template": "^2.0.3", "github-from-package": "0.0.0", - "minimist": "^1.2.0", + "minimist": "^1.2.3", "mkdirp": "^0.5.1", "napi-build-utils": "^1.0.1", "node-abi": "^2.7.0", @@ -12524,24 +12570,6 @@ "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", "dev": true }, - "thenify": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.0.tgz", - "integrity": "sha1-5p44obq+lpsBCCB5eLn2K4hgSDk=", - "dev": true, - "requires": { - "any-promise": "^1.0.0" - } - }, - "thenify-all": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", - "integrity": "sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY=", - "dev": true, - "requires": { - "thenify": ">= 3.1.0 < 4" - } - }, "through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", @@ -14646,4 +14674,4 @@ } } } -} +} \ No newline at end of file diff --git a/package.json b/package.json index d1313804..1afbf734 100644 --- a/package.json +++ b/package.json @@ -71,11 +71,11 @@ "d3": "^4.13.0", "debug": "^4.2.0", "electron": "9.0.0", - "electron-builder": "^22.6.1", + "electron-builder": "^22.7.0", "electron-mocha": "^8.2.0", "electron-notarize": "^0.3.0", "electron-updater": "^4.3.2", - "etcher-sdk": "^4.1.3", + "etcher-sdk": "^4.1.4", "file-loader": "^6.0.0", "flexboxgrid": "^6.3.0", "husky": "^4.2.5", diff --git a/patches/electron-builder-fix-macos-sign.patch b/patches/electron-builder-fix-macos-sign.patch deleted file mode 100644 index 6638e8fc..00000000 --- a/patches/electron-builder-fix-macos-sign.patch +++ /dev/null @@ -1,22 +0,0 @@ -diff --git a/node_modules/app-builder-lib/electron-osx-sign/sign.js b/node_modules/app-builder-lib/electron-osx-sign/sign.js -index 3b85d83c..87da4e57 100644 ---- a/node_modules/app-builder-lib/electron-osx-sign/sign.js -+++ b/node_modules/app-builder-lib/electron-osx-sign/sign.js -@@ -119,6 +119,17 @@ async function verifySignApplicationAsync (opts) { - function signApplicationAsync (opts) { - return walkAsync(getAppContentsPath(opts)) - .then(async function (childPaths) { -+ /** -+ * Sort the child paths by how deep they are in the file tree. Some arcane apple -+ * logic expects the deeper files to be signed first otherwise strange errors get -+ * thrown our way -+ */ -+ childPaths = childPaths.sort((a, b) => { -+ const aDepth = a.split(path.sep).length -+ const bDepth = b.split(path.sep).length -+ return bDepth - aDepth -+ }) -+ - function ignoreFilePath (opts, filePath) { - if (opts.ignore) { - return opts.ignore.some(function (ignore) { diff --git a/tests/gui/models/selection-state.spec.ts b/tests/gui/models/selection-state.spec.ts index ec2661d1..6a690ed9 100644 --- a/tests/gui/models/selection-state.spec.ts +++ b/tests/gui/models/selection-state.spec.ts @@ -549,97 +549,6 @@ describe('Model: selectionState', function () { }).to.throw('Invalid image path: 123'); }); - it('should throw if no extension', function () { - expect(function () { - selectionState.selectImage({ - path: 'foo.img', - size: 999999999, - isSizeEstimated: false, - }); - }).to.throw('Missing image fields: extension'); - }); - - it('should throw if extension is not a string', function () { - expect(function () { - selectionState.selectImage({ - path: 'foo.img', - extension: 1, - size: 999999999, - isSizeEstimated: false, - }); - }).to.throw('Invalid image extension: 1'); - }); - - it("should throw if the extension doesn't match the path and there is no archive extension", function () { - expect(function () { - selectionState.selectImage({ - path: 'foo.img', - extension: 'iso', - size: 999999999, - isSizeEstimated: false, - }); - }).to.throw('Missing image archive extension'); - }); - - it("should throw if the extension doesn't match the path and the archive extension is not a string", function () { - expect(function () { - selectionState.selectImage({ - path: 'foo.img', - extension: 'iso', - archiveExtension: 1, - size: 999999999, - isSizeEstimated: false, - }); - }).to.throw('Missing image archive extension'); - }); - - it("should throw if the archive extension doesn't match the last path extension in a compressed image", function () { - expect(function () { - selectionState.selectImage({ - path: 'foo.img.xz', - extension: 'img', - archiveExtension: 'gz', - size: 999999999, - isSizeEstimated: false, - }); - }).to.throw('Image archive extension mismatch: gz and xz'); - }); - - it('should throw if the extension is not recognised in an uncompressed image', function () { - expect(function () { - selectionState.selectImage({ - path: 'foo.ifg', - extension: 'ifg', - size: 999999999, - isSizeEstimated: false, - }); - }).to.throw('Invalid image extension: ifg'); - }); - - it('should throw if the extension is not recognised in a compressed image', function () { - expect(function () { - selectionState.selectImage({ - path: 'foo.ifg.gz', - extension: 'ifg', - archiveExtension: 'gz', - size: 999999999, - isSizeEstimated: false, - }); - }).to.throw('Invalid image extension: ifg'); - }); - - it('should throw if the archive extension is not recognised', function () { - expect(function () { - selectionState.selectImage({ - path: 'foo.img.ifg', - extension: 'img', - archiveExtension: 'ifg', - size: 999999999, - isSizeEstimated: false, - }); - }).to.throw('Invalid image archive extension: ifg'); - }); - it('should throw if the original size is not a number', function () { expect(function () { selectionState.selectImage({ diff --git a/tests/shared/file-extensions.spec.ts b/tests/shared/file-extensions.spec.ts deleted file mode 100644 index fbd5aa35..00000000 --- a/tests/shared/file-extensions.spec.ts +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright 2017 balena.io - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { expect } from 'chai'; -import * as _ from 'lodash'; - -import * as fileExtensions from '../../lib/shared/file-extensions'; - -describe('Shared: fileExtensions', function () { - describe('.getFileExtensions()', function () { - _.forEach( - [ - // No extension - { - file: 'path/to/filename', - extensions: [], - }, - - // Type: 'archive' - { - file: 'path/to/filename.zip', - extensions: ['zip'], - }, - { - file: 'path/to/filename.etch', - extensions: ['etch'], - }, - - // Type: 'compressed' - { - file: 'path/to/filename.img.gz', - extensions: ['img', 'gz'], - }, - { - file: 'path/to/filename.img.bz2', - extensions: ['img', 'bz2'], - }, - { - file: 'path/to/filename.img.xz', - extensions: ['img', 'xz'], - }, - { - file: 'path/to/filename.img.xz.gz', - extensions: ['img', 'xz', 'gz'], - }, - - // Type: 'image' - { - file: 'path/to/filename.img', - extensions: ['img'], - }, - { - file: 'path/to/filename.iso', - extensions: ['iso'], - }, - { - file: 'path/to/filename.dsk', - extensions: ['dsk'], - }, - { - file: 'path/to/filename.hddimg', - extensions: ['hddimg'], - }, - { - file: 'path/to/filename.raw', - extensions: ['raw'], - }, - { - file: 'path/to/filename.dmg', - extensions: ['dmg'], - }, - ], - (testCase) => { - it(`should return ${testCase.extensions} for ${testCase.file}`, function () { - expect(fileExtensions.getFileExtensions(testCase.file)).to.deep.equal( - testCase.extensions, - ); - }); - }, - ); - - it('should always return lowercase extensions', function () { - const filePath = 'foo.IMG.gZ'; - expect(fileExtensions.getFileExtensions(filePath)).to.deep.equal([ - 'img', - 'gz', - ]); - }); - }); - - describe('.getLastFileExtension()', function () { - it('should return undefined if the file path has no extension', function () { - expect(fileExtensions.getLastFileExtension('foo')).to.equal(null); - }); - - it('should return the extension if there is only one extension', function () { - expect(fileExtensions.getLastFileExtension('foo.img')).to.equal('img'); - }); - - it('should return the last extension if there are two extensions', function () { - expect(fileExtensions.getLastFileExtension('foo.img.gz')).to.equal('gz'); - }); - - it('should return the last extension if there are three extensions', function () { - expect(fileExtensions.getLastFileExtension('foo.bar.img.gz')).to.equal( - 'gz', - ); - }); - }); - - describe('.getPenultimateFileExtension()', function () { - it('should return undefined in the file path has no extension', function () { - expect(fileExtensions.getPenultimateFileExtension('foo')).to.equal(null); - }); - - it('should return undefined if there is only one extension', function () { - expect(fileExtensions.getPenultimateFileExtension('foo.img')).to.equal( - null, - ); - }); - - it('should return the penultimate extension if there are two extensions', function () { - expect(fileExtensions.getPenultimateFileExtension('foo.img.gz')).to.equal( - 'img', - ); - }); - - it('should return the penultimate extension if there are three extensions', function () { - expect( - fileExtensions.getPenultimateFileExtension('foo.bar.img.gz'), - ).to.equal('img'); - }); - }); -}); diff --git a/tests/shared/supported-formats.spec.ts b/tests/shared/supported-formats.spec.ts index f1b284ef..368321b1 100644 --- a/tests/shared/supported-formats.spec.ts +++ b/tests/shared/supported-formats.spec.ts @@ -67,185 +67,6 @@ describe('Shared: SupportedFormats', function () { }); }); - describe('.isSupportedImage()', function () { - _.forEach( - [ - // Type: 'archive' - 'path/to/filename.zip', - 'path/to/filename.etch', - - // Type: 'compressed' - 'path/to/filename.img.gz', - 'path/to/filename.img.bz2', - 'path/to/filename.img.xz', - - // Type: 'image' - 'path/to/filename.img', - 'path/to/filename.iso', - 'path/to/filename.dsk', - 'path/to/filename.hddimg', - 'path/to/filename.raw', - 'path/to/filename.dmg', - 'path/to/filename.sdcard', - 'path/to/filename.wic', - ], - (filename) => { - it(`should return true for ${filename}`, function () { - const isSupported = supportedFormats.isSupportedImage(filename); - expect(isSupported).to.be.true; - }); - }, - ); - - it('should return false if the file has no extension', function () { - const isSupported = supportedFormats.isSupportedImage('/path/to/foo'); - expect(isSupported).to.be.false; - }); - - it('should return false if the extension is not included in .getAllExtensions()', function () { - const isSupported = supportedFormats.isSupportedImage('/path/to/foo.jpg'); - expect(isSupported).to.be.false; - }); - - it('should return true if the extension is included in .getAllExtensions()', function () { - const nonCompressedExtension = _.first( - supportedFormats.getNonCompressedExtensions(), - ); - const imagePath = `/path/to/foo.${nonCompressedExtension}`; - const isSupported = supportedFormats.isSupportedImage(imagePath); - expect(isSupported).to.be.true; - }); - - it('should ignore casing when determining extension validity', function () { - const nonCompressedExtension = _.first( - supportedFormats.getNonCompressedExtensions(), - ); - const imagePath = `/path/to/foo.${_.toUpper(nonCompressedExtension)}`; - const isSupported = supportedFormats.isSupportedImage(imagePath); - expect(isSupported).to.be.true; - }); - - it('should not consider an extension before a non compressed extension', function () { - const nonCompressedExtension = _.first( - supportedFormats.getNonCompressedExtensions(), - ); - const imagePath = `/path/to/foo.1234.${nonCompressedExtension}`; - const isSupported = supportedFormats.isSupportedImage(imagePath); - expect(isSupported).to.be.true; - }); - - it('should return true if the extension is supported and the file name includes dots', function () { - const nonCompressedExtension = _.first( - supportedFormats.getNonCompressedExtensions(), - ); - const imagePath = `/path/to/foo.1.2.3-bar.${nonCompressedExtension}`; - const isSupported = supportedFormats.isSupportedImage(imagePath); - expect(isSupported).to.be.true; - }); - - it('should return true if the extension is only a supported archive extension', function () { - const archiveExtension = _.first(supportedFormats.getArchiveExtensions()); - const imagePath = `/path/to/foo.${archiveExtension}`; - const isSupported = supportedFormats.isSupportedImage(imagePath); - expect(isSupported).to.be.true; - }); - - it('should return true if the extension is a supported one plus a supported compressed extensions', function () { - const nonCompressedExtension = _.first( - supportedFormats.getNonCompressedExtensions(), - ); - const compressedExtension = _.first( - supportedFormats.getCompressedExtensions(), - ); - const imagePath = `/path/to/foo.${nonCompressedExtension}.${compressedExtension}`; - const isSupported = supportedFormats.isSupportedImage(imagePath); - expect(isSupported).to.be.true; - }); - - it('should return false if the extension is an unsupported one plus a supported compressed extensions', function () { - const compressedExtension = _.first( - supportedFormats.getCompressedExtensions(), - ); - const imagePath = `/path/to/foo.jpg.${compressedExtension}`; - const isSupported = supportedFormats.isSupportedImage(imagePath); - expect(isSupported).to.be.false; - }); - - it('should return false if the file has no extension', function () { - const isSupported = supportedFormats.isSupportedImage('/path/to/foo'); - expect(isSupported).to.be.false; - }); - - it('should return false if the extension is not included in .getAllExtensions()', function () { - const isSupported = supportedFormats.isSupportedImage('/path/to/foo.jpg'); - expect(isSupported).to.be.false; - }); - - it('should return true if the extension is included in .getAllExtensions()', function () { - const nonCompressedExtension = _.first( - supportedFormats.getNonCompressedExtensions(), - ); - const imagePath = `/path/to/foo.${nonCompressedExtension}`; - const isSupported = supportedFormats.isSupportedImage(imagePath); - expect(isSupported).to.be.true; - }); - - it('should ignore casing when determining extension validity', function () { - const nonCompressedExtension = _.first( - supportedFormats.getNonCompressedExtensions(), - ); - const imagePath = `/path/to/foo.${_.toUpper(nonCompressedExtension)}`; - const isSupported = supportedFormats.isSupportedImage(imagePath); - expect(isSupported).to.be.true; - }); - - it('should not consider an extension before a non compressed extension', function () { - const nonCompressedExtension = _.first( - supportedFormats.getNonCompressedExtensions(), - ); - const imagePath = `/path/to/foo.1234.${nonCompressedExtension}`; - const isSupported = supportedFormats.isSupportedImage(imagePath); - expect(isSupported).to.be.true; - }); - - it('should return true if the extension is supported and the file name includes dots', function () { - const nonCompressedExtension = _.first( - supportedFormats.getNonCompressedExtensions(), - ); - const imagePath = `/path/to/foo.1.2.3-bar.${nonCompressedExtension}`; - const isSupported = supportedFormats.isSupportedImage(imagePath); - expect(isSupported).to.be.true; - }); - - it('should return true if the extension is only a supported archive extension', function () { - const archiveExtension = _.first(supportedFormats.getArchiveExtensions()); - const imagePath = `/path/to/foo.${archiveExtension}`; - const isSupported = supportedFormats.isSupportedImage(imagePath); - expect(isSupported).to.be.true; - }); - - it('should return true if the extension is a supported one plus a supported compressed extensions', function () { - const nonCompressedExtension = _.first( - supportedFormats.getNonCompressedExtensions(), - ); - const compressedExtension = _.first( - supportedFormats.getCompressedExtensions(), - ); - const imagePath = `/path/to/foo.${nonCompressedExtension}.${compressedExtension}`; - const isSupported = supportedFormats.isSupportedImage(imagePath); - expect(isSupported).to.be.true; - }); - - it('should return false if the extension is an unsupported one plus a supported compressed extensions', function () { - const compressedExtension = _.first( - supportedFormats.getCompressedExtensions(), - ); - const imagePath = `/path/to/foo.jpg.${compressedExtension}`; - const isSupported = supportedFormats.isSupportedImage(imagePath); - expect(isSupported).to.be.false; - }); - }); - describe('.looksLikeWindowsImage()', function () { _.each( [ diff --git a/webpack.config.ts b/webpack.config.ts index da3cea5f..67561937 100644 --- a/webpack.config.ts +++ b/webpack.config.ts @@ -24,7 +24,7 @@ import outdent from 'outdent'; import * as path from 'path'; import * as SimpleProgressWebpackPlugin from 'simple-progress-webpack-plugin'; import * as TerserPlugin from 'terser-webpack-plugin'; -import { BannerPlugin } from 'webpack'; +import { BannerPlugin, NormalModuleReplacementPlugin } from 'webpack'; /** * Don't webpack package.json as mixpanel & sentry tokens @@ -125,6 +125,11 @@ const commonConfig = { test: /\.tsx?$/, use: 'ts-loader', }, + // force axios to use http backend (not xhr) to support streams + replace(/node_modules\/axios\/lib\/defaults\.js$/, { + search: './adapters/xhr', + replace: './adapters/http', + }), // remove bindings magic from drivelist replace( /node_modules\/drivelist\/js\/index\.js$/, @@ -210,6 +215,12 @@ const commonConfig = { new SimpleProgressWebpackPlugin({ format: process.env.WEBPACK_PROGRESS || 'verbose', }), + // Force axios to use http.js, not xhr.js as we need stream support + // (it's package.json file replaces http with xhr for browser targets). + new NormalModuleReplacementPlugin( + /node_modules\/axios\/lib\/adapters\/xhr\.js/, + './http.js', + ), ], output: { path: path.join(__dirname, 'generated'),