Skip to content

Commit

Permalink
Graceful fallback if the renderer process can't access the remote module
Browse files Browse the repository at this point in the history
Right now this module will crash when being ran on a renderer process
that cannot access the `remote` module for determining a default data
path. After this commit, the module will gracefully require users to
call `.setDataPath()` if `remote.app` cannot be accessed.

See: #155
Signed-off-by: Juan Cruz Viotti <[email protected]>
  • Loading branch information
jviotti committed Feb 18, 2021
1 parent d07b2c0 commit 0d89a67
Show file tree
Hide file tree
Showing 5 changed files with 4,532 additions and 81 deletions.
38 changes: 13 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,40 +30,22 @@ You can require this module from either the **main** or **renderer** process (wi
Running on Electron >10 renderer processes
------------------------------------------

When loaded in renderer processes, this module will make use of
When loaded in renderer processes, this module will try to make use of
`electron.remote` in order to fetch the `userData` path.

Electron 10 now [defaults `enableRemoteModule` to
false](https://www.electronjs.org/docs/breaking-changes#default-changed-enableremotemodule-defaults-to-false),
which means that `electron-json-storage` will not work on Electron 10 renderer
processes unless you manually set `enableRemoteModule` to `true`:
which means that `electron-json-storage` will be able to calculate a data path by default.

```js
const win = new BrowserWindow({
webPreferences: {
enableRemoteModule: true
}
})
```

Alternatively, you can avoid using the `remote` module by:

- Passing the `electron.app.getPath('userData')` value from the **main**
process to your **renderer** processes through IPC or a medium of your choice

- Calling `storage.setDataPath()`, on the **renderer** process, with the user
data path obtained on the previous step before calling any other
`electron-json-storage` function.

If you do this, the user data path will be cached by the renderer process,
which will not need to go through the `remote` module to obtain it.
The solution is to manually call `storage.setDataPath()` before reading or
writing any values or setting `enableRemoteModule` to `true`.

Documentation
-------------


* [storage](#module_storage)
* [.getDefaultDataPath()](#module_storage.getDefaultDataPath) ⇒ <code>String</code>
* [.getDefaultDataPath()](#module_storage.getDefaultDataPath) ⇒ <code>String</code> \| <code>Null</code>
* [.setDataPath(directory)](#module_storage.setDataPath)
* [.getDataPath()](#module_storage.getDataPath) ⇒ <code>String</code>
* [.get(key, [options], callback)](#module_storage.get)
Expand All @@ -77,10 +59,15 @@ Documentation

<a name="module_storage.getDefaultDataPath"></a>

### storage.getDefaultDataPath() ⇒ <code>String</code>
### storage.getDefaultDataPath() ⇒ <code>String</code> \| <code>Null</code>
This function will return `null` when running in the
renderer process without support for the `remote` IPC
mechanism. You have to explicitly set a data path using
`.setDataPath()` in these cases.

**Kind**: static method of [<code>storage</code>](#module_storage)
**Summary**: Get the default data path
**Returns**: <code>String</code> - default data path
**Returns**: <code>String</code> \| <code>Null</code> - default data path
**Access**: public
**Example**
```js
Expand Down Expand Up @@ -222,6 +209,7 @@ storage.getAll(function(error, data) {
| [options] | <code>Object</code> | options |
| [options.dataPath] | <code>String</code> | data path |
| [options.validate] | <code>String</code> | validate writes by reading the data back |
| [options.prettyPrinting] | <code>boolean</code> | adds line breaks and spacing to the written data |
| callback | <code>function</code> | callback (error) |

**Example**
Expand Down
26 changes: 4 additions & 22 deletions doc/README.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -30,33 +30,15 @@ You can require this module from either the **main** or **renderer** process (wi
Running on Electron >10 renderer processes
------------------------------------------
When loaded in renderer processes, this module will make use of
When loaded in renderer processes, this module will try to make use of
`electron.remote` in order to fetch the `userData` path.
Electron 10 now [defaults `enableRemoteModule` to
false](https://www.electronjs.org/docs/breaking-changes#default-changed-enableremotemodule-defaults-to-false),
which means that `electron-json-storage` will not work on Electron 10 renderer
processes unless you manually set `enableRemoteModule` to `true`:
```js
const win = new BrowserWindow({
webPreferences: {
enableRemoteModule: true
}
})
```
Alternatively, you can avoid using the `remote` module by:
- Passing the `electron.app.getPath('userData')` value from the **main**
process to your **renderer** processes through IPC or a medium of your choice
- Calling `storage.setDataPath()`, on the **renderer** process, with the user
data path obtained on the previous step before calling any other
`electron-json-storage` function.
which means that `electron-json-storage` will be able to calculate a data path by default.
If you do this, the user data path will be cached by the renderer process,
which will not need to go through the `remote` module to obtain it.
The solution is to manually call `storage.setDataPath()` before reading or
writing any values or setting `enableRemoteModule` to `true`.
Documentation
-------------
Expand Down
8 changes: 7 additions & 1 deletion lib/storage.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,13 @@ const readFile = function(fileName, callback, times) {
* @function
* @public
*
* @returns {String} default data path
* @description
* This function will return `null` when running in the
* renderer process without support for the `remote` IPC
* mechanism. You have to explicitly set a data path using
* `.setDataPath()` in these cases.
*
* @returns {(String|Null)} default data path
*
* @example
* const defaultDataPath = storage.getDefaultDataPath()
Expand Down
13 changes: 11 additions & 2 deletions lib/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
const _ = require('lodash');
const path = require('path');
const electron = require('electron');
const app = electron.app || electron.remote.app;
const app = electron.app || (electron.remote && electron.remote.app) || null;

/**
* @summary Get the default data path
Expand All @@ -40,6 +40,10 @@ const app = electron.app || electron.remote.app;
* const defaultDataPath = utils.getDefaultDataPath()
*/
exports.getDefaultDataPath = function() {
if (!app) {
return null;
}

return path.join(app.getPath('userData'), 'storage');
};

Expand Down Expand Up @@ -123,7 +127,12 @@ exports.getFileName = function(key, options) {
const escapedFileName = encodeURIComponent(keyFileName)
.replace(/\*/g, '-').replace(/%20/g, ' ');

return path.join(options.dataPath || exports.getDataPath(), escapedFileName);
const dataPath = options.dataPath || exports.getDataPath();
if (!dataPath) {
throw new Error('You must explicitly set a data path');
}

return path.join(dataPath, escapedFileName);
};

/**
Expand Down
Loading

0 comments on commit 0d89a67

Please sign in to comment.