diff --git a/app/actions/TrezorActions.js b/app/actions/TrezorActions.js
index 453b3ea113..76d1f2d7e8 100644
--- a/app/actions/TrezorActions.js
+++ b/app/actions/TrezorActions.js
@@ -24,6 +24,7 @@ import {
SIGNMESSAGE_SUCCESS
} from "./ControlActions";
import { getAmountFromTxInputs, getTxFromInputs } from "./TransactionActions";
+import { push as pushHistory } from "connected-react-router";
const session = require("trezor-connect").default;
const {
@@ -82,6 +83,7 @@ export const initTransport = async (session, debug) => {
export const TRZ_CONNECT_ATTEMPT = "TRZ_CONNECT_ATTEMPT";
export const TRZ_CONNECT_FAILED = "TRZ_CONNECT_FAILED";
export const TRZ_CONNECT_SUCCESS = "TRZ_CONNECT_SUCCESS";
+export const TRZ_UDEV_ERROR = "TREZOR_UDEV_ERROR";
export const connect = () => async (dispatch, getState) => {
const {
@@ -97,8 +99,23 @@ export const connect = () => async (dispatch, getState) => {
dispatch({ error, type: TRZ_CONNECT_FAILED });
return;
});
+ try {
+ await dispatch(getFeatures());
+ } catch (err) {
+ dispatch({
+ error: err.message,
+ type: TRZ_CONNECT_FAILED
+ });
+ const needRules = await trezord.needsUdevRules();
+ if (needRules.needs) {
+ dispatch({ type: TRZ_UDEV_ERROR });
+ setTimeout(() => {
+ dispatch(pushHistory("/error"));
+ }, 1000);
+ }
+ return;
+ }
dispatch({ type: TRZ_CONNECT_SUCCESS });
- dispatch(getFeatures());
};
export const TRZ_TREZOR_DISABLED = "TRZ_TREZOR_DISABLED";
@@ -129,7 +146,6 @@ function onChange(dispatch, getState, features) {
if (device == currentDevice) return;
const deviceLabel = features.label;
dispatch({ deviceLabel, device, type: TRZ_SELECTEDDEVICE_CHANGED });
- dispatch(getFeatures());
}
function onConnect(dispatch, getState, features) {
@@ -140,7 +156,6 @@ function onConnect(dispatch, getState, features) {
device = BOOTLOADER_MODE;
}
dispatch({ deviceLabel, device, type: TRZ_LOADDEVICE });
- dispatch(getFeatures());
return device;
}
@@ -330,16 +345,12 @@ async function deviceRun(dispatch, getState, fn) {
export const TRZ_GETFEATURES_SUCCESS = "TRZ_GETFEATURES_SUCCESS";
export const getFeatures = () => async (dispatch, getState) => {
- try {
- const features = await deviceRun(dispatch, getState, async () => {
- const res = await session.getFeatures();
- return res.payload;
- });
- dispatch({ type: TRZ_GETFEATURES_SUCCESS, features });
- return features;
- } catch (error) {
- return null;
- }
+ const features = await deviceRun(dispatch, getState, async () => {
+ const res = await session.getFeatures();
+ return res.payload;
+ });
+ dispatch({ type: TRZ_GETFEATURES_SUCCESS, features });
+ return features;
};
export const TRZ_CANCELOPERATION_SUCCESS = "TRZ_CANCELOPERATION_SUCCESS";
diff --git a/app/components/views/FatalErrorPage/FatalErrorPage.jsx b/app/components/views/FatalErrorPage/FatalErrorPage.jsx
index 2bf12e7242..310eb2ea9c 100644
--- a/app/components/views/FatalErrorPage/FatalErrorPage.jsx
+++ b/app/components/views/FatalErrorPage/FatalErrorPage.jsx
@@ -20,6 +20,7 @@ function FatalErrorPage() {
const {
daemonError,
walletError,
+ trezorUdevError,
isAdvancedDaemon,
shutdownApp,
backToCredentials,
@@ -125,6 +126,14 @@ function FatalErrorPage() {
>
)}
+ {trezorUdevError && (
+ <>
+
+
+
+
+ >
+ )}
@@ -136,6 +145,19 @@ function FatalErrorPage() {
{daemonError && getErrorAction()}
+ {trezorUdevError && (
+
+ https://trezor.io/learn/a/udev-rules
+
+ )
+ }}
+ />
+ )}
{isAdvancedDaemon && (
diff --git a/app/components/views/FatalErrorPage/hooks.js b/app/components/views/FatalErrorPage/hooks.js
index 834cd40320..bd5c2a2f06 100644
--- a/app/components/views/FatalErrorPage/hooks.js
+++ b/app/components/views/FatalErrorPage/hooks.js
@@ -7,6 +7,7 @@ export function useFatalErrorPage() {
const isAdvancedDaemon = useSelector(sel.isAdvancedDaemon);
const daemonError = useSelector(sel.daemonError);
const walletError = useSelector(sel.walletError);
+ const trezorUdevError = useSelector(sel.trezorUdevError);
const shutdownApp = () => dispatch(da.shutdownApp());
const backToCredentials = () => dispatch(da.backToCredentials());
@@ -18,6 +19,7 @@ export function useFatalErrorPage() {
isAdvancedDaemon,
shutdownApp,
backToCredentials,
- deleteDaemonData
+ deleteDaemonData,
+ trezorUdevError
};
}
diff --git a/app/main.development.js b/app/main.development.js
index 809b52dd07..3d40a4d17e 100644
--- a/app/main.development.js
+++ b/app/main.development.js
@@ -64,6 +64,7 @@ import {
removeDcrlnd,
startTrezord,
stopTrezord,
+ needUdevRules,
lnScbInfo,
startDex,
stopDex,
@@ -412,6 +413,8 @@ handle("start-dex", startDex);
handle("stop-dex", stopDex);
+handle("needs-udev-rules", needUdevRules);
+
handle("start-trezord", startTrezord);
handle("stop-trezord", stopTrezord);
diff --git a/app/main_dev/ipc.js b/app/main_dev/ipc.js
index 26f6d0b7bf..8ed7e1c05e 100644
--- a/app/main_dev/ipc.js
+++ b/app/main_dev/ipc.js
@@ -21,6 +21,7 @@ import {
launchTrezord,
GetTrezordPID,
closeTrezord,
+ needsUdevRules,
launchDex,
initCheckDex,
initDexCall,
@@ -251,6 +252,10 @@ export const startDcrlnd = async (
}
};
+export const needUdevRules = () => {
+ return { needs: needsUdevRules() };
+};
+
export const startTrezord = async () => {
if (GetTrezordPID() && GetTrezordPID() !== -1) {
logger.log(
diff --git a/app/main_dev/launch.js b/app/main_dev/launch.js
index d3be524aa6..64fd74f621 100644
--- a/app/main_dev/launch.js
+++ b/app/main_dev/launch.js
@@ -272,6 +272,17 @@ export const closeDcrlnd = () => {
return true;
};
+export function needsUdevRules() {
+ if (os.platform() != "linux") {
+ return false;
+ }
+ const distRules = "/etc/udev/rules.d/51-trezor.rules";
+ if (fs.existsSync(distRules)) {
+ return false;
+ }
+ return true;
+}
+
export function closeTrezord() {
if (trezordPID === -1) {
// process is not started by decrediton
diff --git a/app/reducers/trezor.js b/app/reducers/trezor.js
index 596bd18c51..4ab930fa77 100644
--- a/app/reducers/trezor.js
+++ b/app/reducers/trezor.js
@@ -54,7 +54,8 @@ import {
TRZ_GETWALLETCREATIONMASTERPUBKEY_ATTEMPT,
TRZ_GETWALLETCREATIONMASTERPUBKEY_FAILED,
TRZ_GETWALLETCREATIONMASTERPUBKEY_SUCCESS,
- TRZ_GETFEATURES_SUCCESS
+ TRZ_GETFEATURES_SUCCESS,
+ TRZ_UDEV_ERROR
} from "actions/TrezorActions";
import {
SIGNTX_ATTEMPT,
@@ -77,7 +78,8 @@ export default function trezor(state = {}, action) {
case TRZ_CONNECT_SUCCESS:
return {
...state,
- connectAttempt: false
+ connectAttempt: false,
+ trezorUdevError: false
};
case TRZ_CONNECT_FAILED:
return {
@@ -327,6 +329,11 @@ export default function trezor(state = {}, action) {
};
case CLOSEWALLET_SUCCESS:
return { ...state, enabled: false };
+ case TRZ_UDEV_ERROR:
+ return {
+ ...state,
+ trezorUdevError: true
+ };
default:
return state;
}
diff --git a/app/selectors.js b/app/selectors.js
index 6c1b1e0aca..38c1f5ed11 100644
--- a/app/selectors.js
+++ b/app/selectors.js
@@ -1103,6 +1103,7 @@ export const confirmationDialogModalVisible = bool(
export const isTrezor = get(["trezor", "enabled"]);
export const isPerformingTrezorUpdate = get(["trezor", "performingUpdate"]);
+export const trezorUdevError = get(["trezor", "trezorUdevError"]);
export const isLedger = get(["ledger", "enabled"]);
diff --git a/app/wallet/trezord/index.js b/app/wallet/trezord/index.js
index 89db500946..84844a3f8b 100644
--- a/app/wallet/trezord/index.js
+++ b/app/wallet/trezord/index.js
@@ -1,4 +1,5 @@
import { invocable } from "helpers/electronRenderer";
+export const needsUdevRules = invocable("needs-udev-rules");
export const start = invocable("start-trezord");
export const stop = invocable("stop-trezord");