diff --git a/assets/locales/en.json b/assets/locales/en.json index c1a6a905a..053436fb1 100644 --- a/assets/locales/en.json +++ b/assets/locales/en.json @@ -206,5 +206,9 @@ "startupFailedDialog": { "title": "IPFS Desktop Startup Has Failed", "message": "IPFS node has encountered an error and startup could not be completed:" + }, + "invalidRepositoryDialog": { + "title": "Invalid IPFS Repository or Configuration File", + "message": "The repository at “{ path }” is invalid. The “config” file must be a valid JSON.\n\nBefore starting IPFS Desktop again, please fix the configuration file or rename the old repository to “.ipfs.backup”." } } diff --git a/src/daemon/config.js b/src/daemon/config.js index 72ef3aaec..5042cf9d3 100644 --- a/src/daemon/config.js +++ b/src/daemon/config.js @@ -1,3 +1,4 @@ +const { app, BrowserWindow } = require('electron') const { join } = require('path') const fs = require('fs-extra') const { multiaddr } = require('multiaddr') @@ -315,6 +316,47 @@ async function checkPorts (ipfsd) { logger.info('[daemon] ports updated') } +function checkValidConfig (ipfsd) { + if (!fs.pathExistsSync(ipfsd.path)) { + // If the repository doesn't exist, skip verification. + return true + } + + try { + const stats = fs.statSync(ipfsd.path) + if (!stats.isDirectory()) { + throw new Error('IPFS_PATH must be a directory') + } + + if (!configExists(ipfsd)) { + // Config is generated automatically if it doesn't exist. + return true + } + + // This should catch errors such having no configuration file, + // IPFS_DIR not being a directory, or the configuration file + // being corrupted. + readConfigFile(ipfsd) + return true + } catch (e) { + // Save to error.log + logger.error(e) + + // Hide other windows so the user focus in on the dialog + BrowserWindow.getAllWindows().forEach(w => w.hide()) + + // Show blocking dialog + showDialog({ + title: i18n.t('invalidRepositoryDialog.title'), + message: i18n.t('invalidRepositoryDialog.message', { path: ipfsd.path }), + buttons: [i18n.t('quit')] + }) + + // Only option is to quit + app.quit() + } +} + module.exports = Object.freeze({ configPath, configExists, @@ -322,5 +364,6 @@ module.exports = Object.freeze({ rmApiFile, applyDefaults, migrateConfig, - checkPorts + checkPorts, + checkValidConfig }) diff --git a/src/daemon/daemon.js b/src/daemon/daemon.js index 7fc92e1e3..8611d328b 100644 --- a/src/daemon/daemon.js +++ b/src/daemon/daemon.js @@ -3,7 +3,7 @@ const i18n = require('i18next') const { showDialog } = require('../dialogs') const logger = require('../common/logger') const { getCustomBinary } = require('../custom-ipfs-binary') -const { applyDefaults, migrateConfig, checkPorts, configExists, rmApiFile, apiFileExists } = require('./config') +const { applyDefaults, migrateConfig, checkPorts, configExists, checkValidConfig, rmApiFile, apiFileExists } = require('./config') const showMigrationPrompt = require('./migration-prompt') function cannotConnectDialog (addr) { @@ -40,6 +40,10 @@ async function spawn ({ flags, path }) { args: flags }) + if (!checkValidConfig(ipfsd)) { + throw new Error(`repository at ${ipfsd.path} is invalid`) + } + if (configExists(ipfsd)) { migrateConfig(ipfsd) return { ipfsd, isRemote: false } @@ -166,7 +170,16 @@ async function startIpfsWithLogs (ipfsd) { } module.exports = async function (opts) { - const { ipfsd, isRemote } = await spawn(opts) + let ipfsd, isRemote + + try { + const res = await spawn(opts) + ipfsd = res.ipfsd + isRemote = res.isRemote + } catch (err) { + return { err: err.toString() } + } + if (!isRemote) { await checkPorts(ipfsd) }