Skip to content

Commit cc75a1c

Browse files
hacdiaslidel
andauthored
fix: detect invalid or corrupted repository (#2067)
* fix: detect invalid repository * refactor: move checkValidConfig to config.js * fix: handle errors and existing better * fix: hide BrowserWindows before showing dialog on Linux we show webui on startup because tray icon is not always available, and showDialog's blocking nature freezes it mid-load. What is worse, that broken BrowserWindow may be on top of the dialog, leaving user unaware of error and confused why everything froze. This solves the problem by hiding all windows before showing the final dialog Co-authored-by: Marcin Rataj <[email protected]>
1 parent c00f222 commit cc75a1c

File tree

3 files changed

+63
-3
lines changed

3 files changed

+63
-3
lines changed

Diff for: assets/locales/en.json

+4
Original file line numberDiff line numberDiff line change
@@ -206,5 +206,9 @@
206206
"startupFailedDialog": {
207207
"title": "IPFS Desktop Startup Has Failed",
208208
"message": "IPFS node has encountered an error and startup could not be completed:"
209+
},
210+
"invalidRepositoryDialog": {
211+
"title": "Invalid IPFS Repository or Configuration File",
212+
"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”."
209213
}
210214
}

Diff for: src/daemon/config.js

+44-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
const { app, BrowserWindow } = require('electron')
12
const { join } = require('path')
23
const fs = require('fs-extra')
34
const { multiaddr } = require('multiaddr')
@@ -330,12 +331,54 @@ async function checkPorts (ipfsd) {
330331
logger.info('[daemon] ports updated')
331332
}
332333

334+
function checkValidConfig (ipfsd) {
335+
if (!fs.pathExistsSync(ipfsd.path)) {
336+
// If the repository doesn't exist, skip verification.
337+
return true
338+
}
339+
340+
try {
341+
const stats = fs.statSync(ipfsd.path)
342+
if (!stats.isDirectory()) {
343+
throw new Error('IPFS_PATH must be a directory')
344+
}
345+
346+
if (!configExists(ipfsd)) {
347+
// Config is generated automatically if it doesn't exist.
348+
return true
349+
}
350+
351+
// This should catch errors such having no configuration file,
352+
// IPFS_DIR not being a directory, or the configuration file
353+
// being corrupted.
354+
readConfigFile(ipfsd)
355+
return true
356+
} catch (e) {
357+
// Save to error.log
358+
logger.error(e)
359+
360+
// Hide other windows so the user focus in on the dialog
361+
BrowserWindow.getAllWindows().forEach(w => w.hide())
362+
363+
// Show blocking dialog
364+
showDialog({
365+
title: i18n.t('invalidRepositoryDialog.title'),
366+
message: i18n.t('invalidRepositoryDialog.message', { path: ipfsd.path }),
367+
buttons: [i18n.t('quit')]
368+
})
369+
370+
// Only option is to quit
371+
app.quit()
372+
}
373+
}
374+
333375
module.exports = Object.freeze({
334376
configPath,
335377
configExists,
336378
apiFileExists,
337379
rmApiFile,
338380
applyDefaults,
339381
migrateConfig,
340-
checkPorts
382+
checkPorts,
383+
checkValidConfig
341384
})

Diff for: src/daemon/daemon.js

+15-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ const i18n = require('i18next')
33
const { showDialog } = require('../dialogs')
44
const logger = require('../common/logger')
55
const { getCustomBinary } = require('../custom-ipfs-binary')
6-
const { applyDefaults, migrateConfig, checkPorts, configExists, rmApiFile, apiFileExists } = require('./config')
6+
const { applyDefaults, migrateConfig, checkPorts, configExists, checkValidConfig, rmApiFile, apiFileExists } = require('./config')
77
const showMigrationPrompt = require('./migration-prompt')
88

99
function cannotConnectDialog (addr) {
@@ -40,6 +40,10 @@ async function spawn ({ flags, path }) {
4040
args: flags
4141
})
4242

43+
if (!checkValidConfig(ipfsd)) {
44+
throw new Error(`repository at ${ipfsd.path} is invalid`)
45+
}
46+
4347
if (configExists(ipfsd)) {
4448
migrateConfig(ipfsd)
4549
return { ipfsd, isRemote: false }
@@ -166,7 +170,16 @@ async function startIpfsWithLogs (ipfsd) {
166170
}
167171

168172
module.exports = async function (opts) {
169-
const { ipfsd, isRemote } = await spawn(opts)
173+
let ipfsd, isRemote
174+
175+
try {
176+
const res = await spawn(opts)
177+
ipfsd = res.ipfsd
178+
isRemote = res.isRemote
179+
} catch (err) {
180+
return { err: err.toString() }
181+
}
182+
170183
if (!isRemote) {
171184
await checkPorts(ipfsd)
172185
}

0 commit comments

Comments
 (0)